@basou/core 0.44.0 → 0.46.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 +1186 -712
- package/dist/index.js +3865 -3479
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/schemas/approval.schema.json +7 -7
- package/schemas/event.schema.json +45 -45
- package/schemas/manifest.schema.json +5 -5
- package/schemas/retired/0.1.0/approval.schema.json +119 -0
- package/schemas/retired/0.1.0/manifest.schema.json +264 -0
- package/schemas/retired/0.1.0/session-import.schema.json +1703 -0
- package/schemas/retired/0.1.0/session.schema.json +254 -0
- package/schemas/retired/0.1.0/task.schema.json +84 -0
- package/schemas/retired/0.2.0/event.schema.json +1452 -0
- package/schemas/session-import.schema.json +55 -55
- package/schemas/session.schema.json +9 -9
- package/schemas/status.schema.json +2 -2
- package/schemas/task-index.schema.json +4 -4
- package/schemas/task.schema.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -106,6 +106,19 @@ declare function removeStopHook(settings: unknown): StopHookRemoval;
|
|
|
106
106
|
/** Return the installed basou Stop hook command, or null if none is registered. */
|
|
107
107
|
declare function findBasouStopHookCommand(settings: unknown): string | null;
|
|
108
108
|
|
|
109
|
+
/**
|
|
110
|
+
* `schema_version` stamped on NEWLY WRITTEN `.basou/manifest.yaml`.
|
|
111
|
+
*
|
|
112
|
+
* 0.2.0 requires seconds in every timestamp. That NARROWS the field's domain,
|
|
113
|
+
* which §7.3 forbids except under the vacuous-narrowing rule the same section
|
|
114
|
+
* states: no value basou has ever written omits seconds, so the set of
|
|
115
|
+
* documents this refuses is empty. See `docs/spec/schemas.md` for the read
|
|
116
|
+
* rule and the measurement. The narrowing is shared with the event format, so
|
|
117
|
+
* every durable document bumps together.
|
|
118
|
+
*
|
|
119
|
+
* Note: basou writes this document.
|
|
120
|
+
*/
|
|
121
|
+
declare const MANIFEST_SCHEMA_VERSION: "0.2.0";
|
|
109
122
|
/**
|
|
110
123
|
* The manifest, plus one guard the loose object cannot express: a TOP-LEVEL
|
|
111
124
|
* `confidential` is refused. It belongs under `policies`, and because the
|
|
@@ -278,9 +291,17 @@ declare const SessionInnerImportSchema: z.ZodObject<{
|
|
|
278
291
|
* validates a payload against the published artifact gets the same answer the
|
|
279
292
|
* importer will give, instead of passing validation and being rejected at run
|
|
280
293
|
* time. Unrelated to the events INSIDE the envelope, which carry their own
|
|
281
|
-
* `schema_version` and are at 0.
|
|
294
|
+
* `schema_version` and are at 0.3.0.
|
|
295
|
+
*
|
|
296
|
+
* Bumped to 0.2.0 when timestamps began requiring seconds. That narrowing
|
|
297
|
+
* reaches the envelope's OWN fields -- `session.started_at`, `session.ended_at`
|
|
298
|
+
* and both `active_intervals` bounds -- so unlike the 0.2.0 event bump, whose
|
|
299
|
+
* bytes changed only because of the union it embeds, the envelope's own
|
|
300
|
+
* accepted set moved and the `$id` moves with it. A third party still gets one
|
|
301
|
+
* answer from the artifact and the importer, which is the whole point of
|
|
302
|
+
* pinning the version here.
|
|
282
303
|
*/
|
|
283
|
-
declare const SESSION_IMPORT_SCHEMA_VERSION: "0.
|
|
304
|
+
declare const SESSION_IMPORT_SCHEMA_VERSION: "0.2.0";
|
|
284
305
|
declare const SessionImportPayloadSchema: z.ZodObject<{
|
|
285
306
|
schema_version: z.ZodString;
|
|
286
307
|
session: z.ZodObject<{
|
|
@@ -802,6 +823,21 @@ type StopHookEvaluation = ({
|
|
|
802
823
|
* before, so consumers that read only the capture signal are unaffected.
|
|
803
824
|
*/
|
|
804
825
|
declare function evaluateStopHook(input: StopHookEvaluationInput): StopHookEvaluation;
|
|
826
|
+
/**
|
|
827
|
+
* When the session this transcript belongs to started: the timestamp of its
|
|
828
|
+
* first record that carries a parseable one.
|
|
829
|
+
*
|
|
830
|
+
* Used to date what the session is HOLDING. Anything the session read at start
|
|
831
|
+
* — its instruction files, the protocols rendered into them — is the version
|
|
832
|
+
* that existed at this instant, so a managed block whose stamp says it changed
|
|
833
|
+
* after it is newer than the copy in that session's context.
|
|
834
|
+
*
|
|
835
|
+
* Not every record carries a timestamp (a leading `summary` record does not),
|
|
836
|
+
* so this scans forward rather than reading `records[0]` and giving up.
|
|
837
|
+
* `undefined` means the transcript never said, and callers then say nothing
|
|
838
|
+
* rather than guess a start.
|
|
839
|
+
*/
|
|
840
|
+
declare function transcriptStartedAt(records: ClaudeTranscriptRecord[]): string | undefined;
|
|
805
841
|
|
|
806
842
|
/** Alias kept for API symmetry with the claude-code adapter's `CommandLookup`. */
|
|
807
843
|
type CodexCommandLookup = CommandLookup;
|
|
@@ -1016,6 +1052,19 @@ type CodexRolloutToPayloadOptions = {
|
|
|
1016
1052
|
*/
|
|
1017
1053
|
declare function codexRolloutToImportPayload(records: ReadonlyArray<CodexRolloutRecord>, options: CodexRolloutToPayloadOptions): SessionImportPayload | null;
|
|
1018
1054
|
|
|
1055
|
+
/**
|
|
1056
|
+
* `schema_version` stamped on NEWLY WRITTEN `.basou/approvals/**`.
|
|
1057
|
+
*
|
|
1058
|
+
* 0.2.0 requires seconds in every timestamp. That NARROWS the field's domain,
|
|
1059
|
+
* which §7.3 forbids except under the vacuous-narrowing rule the same section
|
|
1060
|
+
* states: no value basou has ever written omits seconds, so the set of
|
|
1061
|
+
* documents this refuses is empty. See `docs/spec/schemas.md` for the read
|
|
1062
|
+
* rule and the measurement. The narrowing is shared with the event format, so
|
|
1063
|
+
* every durable document bumps together.
|
|
1064
|
+
*
|
|
1065
|
+
* Note: basou only READS this document -- approvals are placed by an outside orchestrator, so nothing in this tree stamps the version; the constant exists so the published artifact and the accepted set are declared in one place.
|
|
1066
|
+
*/
|
|
1067
|
+
declare const APPROVAL_SCHEMA_VERSION: "0.2.0";
|
|
1019
1068
|
/**
|
|
1020
1069
|
* Lifecycle states of a Basou approval. The status is stored directly on
|
|
1021
1070
|
* the approval YAML (flat shape) so that pending → resolved transitions
|
|
@@ -1177,9 +1226,16 @@ declare function enumerateApprovals(paths: BasouPaths): Promise<{
|
|
|
1177
1226
|
declare function isLazyExpired(approval: Approval, now: Date): boolean;
|
|
1178
1227
|
|
|
1179
1228
|
/**
|
|
1180
|
-
* `schema_version` stamped on NEWLY WRITTEN events.
|
|
1181
|
-
*
|
|
1182
|
-
*
|
|
1229
|
+
* `schema_version` stamped on NEWLY WRITTEN events.
|
|
1230
|
+
*
|
|
1231
|
+
* 0.3.0 requires seconds in every timestamp. That NARROWS the field's domain,
|
|
1232
|
+
* which §7.3 forbids except under the vacuous-narrowing rule the same section
|
|
1233
|
+
* states: no value basou has ever written omits seconds, so the set of
|
|
1234
|
+
* documents this refuses is empty. See `docs/spec/schemas.md` for the read
|
|
1235
|
+
* rule and the measurement.
|
|
1236
|
+
*
|
|
1237
|
+
* 0.2.0 made `command_executed.duration_ms` nullable, which widened the
|
|
1238
|
+
* field's domain and so is a breaking change to the format.
|
|
1183
1239
|
*
|
|
1184
1240
|
* The bump does not change what any value already on disk means: `0` meant "not
|
|
1185
1241
|
* observed" before and still does. What changes is that a writer now says so
|
|
@@ -1188,13 +1244,17 @@ declare function isLazyExpired(approval: Approval, now: Date): boolean;
|
|
|
1188
1244
|
* `readObservedDuration`), and the
|
|
1189
1245
|
* version is a statement about validation, not about interpretation.
|
|
1190
1246
|
*
|
|
1191
|
-
* Reading is unaffected — {@link SchemaVersionSchema}
|
|
1192
|
-
* events already on disk keep validating, and are not
|
|
1193
|
-
* session IS re-derived, and restamped, when its source
|
|
1194
|
-
*
|
|
1195
|
-
*
|
|
1247
|
+
* Reading is unaffected by the 0.2.0 bump — {@link SchemaVersionSchema}
|
|
1248
|
+
* accepts any 0.x.y — so events already on disk keep validating, and are not
|
|
1249
|
+
* rewritten in place (a session IS re-derived, and restamped, when its source
|
|
1250
|
+
* log grows). The 0.3.0 narrowing is what a stored value IS checked against,
|
|
1251
|
+
* which is why it had to be empty of real documents before it could land.
|
|
1252
|
+
*
|
|
1253
|
+
* The 0.3.0 timestamp narrowing is shared, so the other durable documents
|
|
1254
|
+
* (manifest, session, task, approval) bump alongside it. The two caches
|
|
1255
|
+
* (`status`, `task-index`) are rebuilt rather than versioned.
|
|
1196
1256
|
*/
|
|
1197
|
-
declare const EVENT_SCHEMA_VERSION: "0.
|
|
1257
|
+
declare const EVENT_SCHEMA_VERSION: "0.3.0";
|
|
1198
1258
|
declare const SessionStartedEventSchema: z.ZodObject<{
|
|
1199
1259
|
schema_version: z.ZodString;
|
|
1200
1260
|
id: z.ZodString & z.ZodType<`evt_${string}`, string, z.core.$ZodTypeInternals<`evt_${string}`, string>>;
|
|
@@ -1911,747 +1971,963 @@ declare function replayEvents(sessionDir: string, options?: ReplayOptions): Asyn
|
|
|
1911
1971
|
declare function readAllEvents(sessionDir: string, options?: ReplayOptions): Promise<Event[]>;
|
|
1912
1972
|
|
|
1913
1973
|
/**
|
|
1914
|
-
*
|
|
1915
|
-
* once in the manifest's `repos` list; the capture config (`source_roots`) must
|
|
1916
|
-
* cover every declared repo. This computes the drift between the two so
|
|
1917
|
-
* `basou project check` can surface a declared repo that is NOT being captured
|
|
1918
|
-
* — the class of bug where a companion repo was wired into the workspace but
|
|
1919
|
-
* never added to `source_roots`, so its work silently fell out of capture.
|
|
1974
|
+
* `schema_version` stamped on NEWLY WRITTEN `.basou/sessions/<id>/session.yaml`.
|
|
1920
1975
|
*
|
|
1921
|
-
*
|
|
1922
|
-
*
|
|
1923
|
-
*
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
*
|
|
1928
|
-
*
|
|
1929
|
-
* `ja` for a single audience, `en+ja` when both are served.
|
|
1930
|
-
*/
|
|
1931
|
-
type RepoLanguage = "en" | "ja" | "en+ja";
|
|
1932
|
-
/** A published surface a repo emits: a deployed website or a package registry. */
|
|
1933
|
-
type PublishKind = "web" | "npm";
|
|
1934
|
-
/**
|
|
1935
|
-
* Where a repo's agent instruction files live (the instruction-source axis),
|
|
1936
|
-
* independent of visibility / language / publishes. `hub` is basou's native,
|
|
1937
|
-
* generated hub-and-spoke topology (canonical in the anchor, gitignored symlinks
|
|
1938
|
-
* in each repo); `self` is the additive opt-in where the canonical AGENTS.md is a
|
|
1939
|
-
* regular committed file in the repo itself and basou stays hands-off about its
|
|
1940
|
-
* content. See {@link instructionMode} for the default (absent => `hub`).
|
|
1941
|
-
*/
|
|
1942
|
-
type RepoInstructions = "hub" | "self";
|
|
1943
|
-
/**
|
|
1944
|
-
* One published surface. Its visibility and language are INDEPENDENT of the
|
|
1945
|
-
* source repo's: a private repo commonly publishes a public website. Both are
|
|
1946
|
-
* optional so a surface can be declared
|
|
1947
|
-
* before those facts are pinned down (mirroring how `adopt` leaves repo
|
|
1948
|
-
* visibility unset for the operator to fill in).
|
|
1949
|
-
*/
|
|
1950
|
-
type PublishTarget = {
|
|
1951
|
-
kind: PublishKind;
|
|
1952
|
-
visibility?: RepoVisibility | undefined;
|
|
1953
|
-
language?: RepoLanguage | undefined;
|
|
1954
|
-
};
|
|
1955
|
-
type RepoEntry = {
|
|
1956
|
-
/** Path relative to the manifest repo root (e.g. ".", "../takuhon"). */
|
|
1957
|
-
path: string;
|
|
1958
|
-
visibility?: RepoVisibility | undefined;
|
|
1959
|
-
/** Source language (commits/comments/code, read by contributors). Independent of visibility. */
|
|
1960
|
-
language?: RepoLanguage | undefined;
|
|
1961
|
-
/** Published surfaces this repo emits (opt-in; absent for a repo that publishes nothing). */
|
|
1962
|
-
publishes?: PublishTarget[] | undefined;
|
|
1963
|
-
/**
|
|
1964
|
-
* Instruction-source mode. Absent => `hub` (basou's native generated topology),
|
|
1965
|
-
* so an existing roster's behavior is unchanged. `self` opts the repo out of
|
|
1966
|
-
* generation: its AGENTS.md is a hand-authored committed file and basou stays
|
|
1967
|
-
* hands-off. Resolve the effective mode with {@link instructionMode}.
|
|
1968
|
-
*/
|
|
1969
|
-
instructions?: RepoInstructions | undefined;
|
|
1970
|
-
};
|
|
1971
|
-
/**
|
|
1972
|
-
* The effective instruction-source mode for a repo: the declared `instructions`,
|
|
1973
|
-
* defaulting to `hub` when absent. The default is the single guarantee that an
|
|
1974
|
-
* existing roster (which has no `instructions` field) keeps basou's current
|
|
1975
|
-
* hub-and-spoke behavior byte-for-byte — every generator branches on this, never
|
|
1976
|
-
* on the raw optional field, so "absent => hub" is decided in exactly one place.
|
|
1976
|
+
* 0.2.0 requires seconds in every timestamp. That NARROWS the field's domain,
|
|
1977
|
+
* which §7.3 forbids except under the vacuous-narrowing rule the same section
|
|
1978
|
+
* states: no value basou has ever written omits seconds, so the set of
|
|
1979
|
+
* documents this refuses is empty. See `docs/spec/schemas.md` for the read
|
|
1980
|
+
* rule and the measurement. The narrowing is shared with the event format, so
|
|
1981
|
+
* every durable document bumps together.
|
|
1982
|
+
*
|
|
1983
|
+
* Note: basou writes this document.
|
|
1977
1984
|
*/
|
|
1978
|
-
declare
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
};
|
|
1985
|
+
declare const SESSION_SCHEMA_VERSION: "0.2.0";
|
|
1986
|
+
/** Session lifecycle states. */
|
|
1987
|
+
declare const SessionStatusSchema: z.ZodEnum<{
|
|
1988
|
+
initialized: "initialized";
|
|
1989
|
+
running: "running";
|
|
1990
|
+
waiting_approval: "waiting_approval";
|
|
1991
|
+
completed: "completed";
|
|
1992
|
+
failed: "failed";
|
|
1993
|
+
interrupted: "interrupted";
|
|
1994
|
+
imported: "imported";
|
|
1995
|
+
archived: "archived";
|
|
1996
|
+
}>;
|
|
1997
|
+
/** Inferred runtime type for {@link SessionStatusSchema}. */
|
|
1998
|
+
type SessionStatus = z.infer<typeof SessionStatusSchema>;
|
|
1993
1999
|
/**
|
|
1994
|
-
*
|
|
1995
|
-
*
|
|
1996
|
-
*
|
|
1997
|
-
*
|
|
1998
|
-
*
|
|
2000
|
+
* Source kind that produced the session.
|
|
2001
|
+
*
|
|
2002
|
+
* - `claude-code-adapter` — a live `basou run claude-code` process wrap.
|
|
2003
|
+
* - `claude-code-import` — derived after the fact from a Claude Code native
|
|
2004
|
+
* transcript (`~/.claude/projects/*.jsonl`) by `basou import claude-code`.
|
|
2005
|
+
* - `codex-adapter` — a live `basou run codex` process wrap.
|
|
2006
|
+
* - `codex-import` — derived after the fact from an OpenAI Codex native
|
|
2007
|
+
* rollout log (date-partitioned `~/.codex/sessions`) by `basou import codex`.
|
|
2008
|
+
* - `import` — a round-trip of a Basou-format export (`basou session import`).
|
|
2009
|
+
* - `human` / `terminal` — manually-authored / terminal-recorded sessions.
|
|
1999
2010
|
*/
|
|
2000
|
-
declare
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
/** Declared repo paths (normalized) that were appended because `source_roots` did not cover them. */
|
|
2012
|
-
added: string[];
|
|
2013
|
-
/** True when `source_roots` already covers every declared repo (`next` equals the current list). */
|
|
2014
|
-
unchanged: boolean;
|
|
2015
|
-
};
|
|
2011
|
+
declare const SessionSourceKindSchema: z.ZodEnum<{
|
|
2012
|
+
"claude-code-adapter": "claude-code-adapter";
|
|
2013
|
+
import: "import";
|
|
2014
|
+
"claude-code-import": "claude-code-import";
|
|
2015
|
+
"codex-adapter": "codex-adapter";
|
|
2016
|
+
"codex-import": "codex-import";
|
|
2017
|
+
human: "human";
|
|
2018
|
+
terminal: "terminal";
|
|
2019
|
+
}>;
|
|
2020
|
+
/** Inferred runtime type for {@link SessionSourceKindSchema}. */
|
|
2021
|
+
type SessionSourceKind = z.infer<typeof SessionSourceKindSchema>;
|
|
2016
2022
|
/**
|
|
2017
|
-
*
|
|
2018
|
-
*
|
|
2019
|
-
* project; this is the actuator behind `basou project sync`, computing the
|
|
2020
|
-
* additive reconciliation so every declared repo is captured.
|
|
2023
|
+
* Optional per-session metrics, computed at import time from the source tool's
|
|
2024
|
+
* native log. Two groups, both optional because not every source records them:
|
|
2021
2025
|
*
|
|
2022
|
-
*
|
|
2023
|
-
*
|
|
2024
|
-
*
|
|
2025
|
-
*
|
|
2026
|
-
* the
|
|
2027
|
-
*
|
|
2026
|
+
* - Model-usage rollup (`*_tokens`): the transcript carries per-message token
|
|
2027
|
+
* usage; these are the session totals. `reasoning_output_tokens` is
|
|
2028
|
+
* Codex-only, and live `run`/`exec` sessions carry no token usage at all.
|
|
2029
|
+
* - Engaged-time metrics (`active_*`): the billing-oriented active time derived
|
|
2030
|
+
* from the session's genuine engagement timestamps (conversation turns plus
|
|
2031
|
+
* action events), with idle gaps capped. `active_intervals` are the merged
|
|
2032
|
+
* wall-clock ranges (so cross-session totals can de-duplicate overlapping
|
|
2033
|
+
* work by interval union); `active_time_ms` is their summed duration;
|
|
2034
|
+
* `active_gap_cap_ms` and `active_time_method` lock the methodology so the
|
|
2035
|
+
* stored numbers stay interpretable if the method changes later. When a
|
|
2036
|
+
* source records explicit per-turn intervals (Codex), `active_time_method` is
|
|
2037
|
+
* `turn-intervals` and the in-turn time is the log's real wall-clock span
|
|
2038
|
+
* rather than a gap-capped approximation; the active semantics are unchanged.
|
|
2039
|
+
* - `machine_active_time_ms`: model compute time — the summed duration of the
|
|
2040
|
+
* source's per-turn spans (Codex `task_complete.duration_ms`), a SUBSET of a
|
|
2041
|
+
* single session's engaged active time. Unlike `active_intervals` it is a
|
|
2042
|
+
* plain sum, NOT wall-clock-deduplicated, so two concurrent sessions can sum
|
|
2043
|
+
* past their billable (union) active wall-clock — that is intended (two models
|
|
2044
|
+
* working at once did two machine-hours in one wall-clock hour). Captured only
|
|
2045
|
+
* for sources that record per-turn duration (Codex); absent otherwise.
|
|
2028
2046
|
*
|
|
2029
|
-
*
|
|
2030
|
-
*
|
|
2031
|
-
*
|
|
2047
|
+
* Absent on sessions imported before a given field existed (re-import to
|
|
2048
|
+
* backfill). Live sessions carry no engaged-time metrics and fall back to
|
|
2049
|
+
* event-derived active time at stats time.
|
|
2032
2050
|
*/
|
|
2033
|
-
declare
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2051
|
+
declare const SessionMetricsSchema: z.ZodObject<{
|
|
2052
|
+
output_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2053
|
+
input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2054
|
+
cached_input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2055
|
+
reasoning_output_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2056
|
+
active_time_ms: z.ZodOptional<z.ZodNumber>;
|
|
2057
|
+
active_intervals: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
2058
|
+
start: z.ZodString;
|
|
2059
|
+
end: z.ZodString;
|
|
2060
|
+
}, z.core.$loose>>>;
|
|
2061
|
+
active_gap_cap_ms: z.ZodOptional<z.ZodNumber>;
|
|
2062
|
+
active_time_method: z.ZodOptional<z.ZodString>;
|
|
2063
|
+
machine_active_time_ms: z.ZodOptional<z.ZodNumber>;
|
|
2064
|
+
}, z.core.$loose>;
|
|
2065
|
+
/** Inferred runtime type for {@link SessionMetricsSchema}. */
|
|
2066
|
+
type SessionMetrics = z.infer<typeof SessionMetricsSchema>;
|
|
2037
2067
|
/**
|
|
2038
|
-
*
|
|
2039
|
-
*
|
|
2040
|
-
*
|
|
2041
|
-
*
|
|
2068
|
+
* Tamper-evidence head anchor for a session whose `events.jsonl` is hash
|
|
2069
|
+
* chained: `head_hash` is the hex sha-256 of the last written event line
|
|
2070
|
+
* (excluding the trailing newline), `event_count` the number of chained lines.
|
|
2071
|
+
* Written by the import / in-place re-import writers and, for a live session
|
|
2072
|
+
* (`exec` / `run` / ad-hoc), by the finalize once it reaches a terminal status.
|
|
2073
|
+
* Absent on a still-live session (the anchor is stamped at finalize) and on a
|
|
2074
|
+
* pre-feature unchained session. Additive optional => no schema_version bump.
|
|
2075
|
+
* `.strict()` because the writers fully own the shape.
|
|
2042
2076
|
*/
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
};
|
|
2050
|
-
type RosterAdoptionPlan = {
|
|
2051
|
-
/** Proposed `repos` entries: the candidates that are git repos (visibility left unset for the operator). */
|
|
2052
|
-
repos: RepoEntry[];
|
|
2053
|
-
/** Candidates excluded from the roster, with why (a non-repo directory, or an unresolvable path). */
|
|
2054
|
-
excluded: {
|
|
2055
|
-
path: string;
|
|
2056
|
-
kind: Exclude<AdoptCandidateKind, "repo">;
|
|
2057
|
-
}[];
|
|
2058
|
-
};
|
|
2077
|
+
declare const SessionIntegritySchema: z.ZodObject<{
|
|
2078
|
+
head_hash: z.ZodString;
|
|
2079
|
+
event_count: z.ZodNumber;
|
|
2080
|
+
}, z.core.$strict>;
|
|
2081
|
+
/** Inferred runtime type for {@link SessionIntegritySchema}. */
|
|
2082
|
+
type SessionIntegrity = z.infer<typeof SessionIntegritySchema>;
|
|
2059
2083
|
/**
|
|
2060
|
-
*
|
|
2061
|
-
*
|
|
2062
|
-
*
|
|
2063
|
-
* `kind` is the caller's job, so this stays testable without disk I/O.
|
|
2064
|
-
*
|
|
2065
|
-
* A git repo becomes a roster entry (path only; visibility is left unset because
|
|
2066
|
-
* it is a human judgment, kept independent of the other axes). A non-repo
|
|
2067
|
-
* (commonly the generated workspace view) or an unresolvable path is excluded and
|
|
2068
|
-
* reported, so the operator sees what was dropped and why before editing. Repo
|
|
2069
|
-
* paths are deduped by normalized form, preserving the first declared form and
|
|
2070
|
-
* order.
|
|
2084
|
+
* Schema for `.basou/sessions/<session_id>/session.yaml`. The minimal
|
|
2085
|
+
* session document carries the actual fields nested under the outer
|
|
2086
|
+
* `session:` key.
|
|
2071
2087
|
*/
|
|
2072
|
-
declare
|
|
2088
|
+
declare const SessionSchema: z.ZodObject<{
|
|
2089
|
+
schema_version: z.ZodString;
|
|
2090
|
+
session: z.ZodObject<{
|
|
2091
|
+
id: z.ZodString & z.ZodType<`ses_${string}`, string, z.core.$ZodTypeInternals<`ses_${string}`, string>>;
|
|
2092
|
+
label: z.ZodOptional<z.ZodString>;
|
|
2093
|
+
task_id: z.ZodOptional<z.ZodNullable<z.ZodString & z.ZodType<`task_${string}`, string, z.core.$ZodTypeInternals<`task_${string}`, string>>>>;
|
|
2094
|
+
workspace_id: z.ZodString & z.ZodType<`ws_${string}`, string, z.core.$ZodTypeInternals<`ws_${string}`, string>>;
|
|
2095
|
+
source: z.ZodObject<{
|
|
2096
|
+
kind: z.ZodEnum<{
|
|
2097
|
+
"claude-code-adapter": "claude-code-adapter";
|
|
2098
|
+
import: "import";
|
|
2099
|
+
"claude-code-import": "claude-code-import";
|
|
2100
|
+
"codex-adapter": "codex-adapter";
|
|
2101
|
+
"codex-import": "codex-import";
|
|
2102
|
+
human: "human";
|
|
2103
|
+
terminal: "terminal";
|
|
2104
|
+
}>;
|
|
2105
|
+
version: z.ZodLiteral<"0.1.0">;
|
|
2106
|
+
external_id: z.ZodOptional<z.ZodString>;
|
|
2107
|
+
source_size_bytes: z.ZodOptional<z.ZodNumber>;
|
|
2108
|
+
}, z.core.$loose>;
|
|
2109
|
+
started_at: z.ZodString;
|
|
2110
|
+
ended_at: z.ZodOptional<z.ZodString>;
|
|
2111
|
+
status: z.ZodEnum<{
|
|
2112
|
+
initialized: "initialized";
|
|
2113
|
+
running: "running";
|
|
2114
|
+
waiting_approval: "waiting_approval";
|
|
2115
|
+
completed: "completed";
|
|
2116
|
+
failed: "failed";
|
|
2117
|
+
interrupted: "interrupted";
|
|
2118
|
+
imported: "imported";
|
|
2119
|
+
archived: "archived";
|
|
2120
|
+
}>;
|
|
2121
|
+
working_directory: z.ZodString;
|
|
2122
|
+
invocation: z.ZodObject<{
|
|
2123
|
+
command: z.ZodString;
|
|
2124
|
+
args: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
2125
|
+
exit_code: z.ZodNullable<z.ZodNumber>;
|
|
2126
|
+
}, z.core.$loose>;
|
|
2127
|
+
related_files: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
2128
|
+
events_log: z.ZodDefault<z.ZodString>;
|
|
2129
|
+
summary: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
2130
|
+
metrics: z.ZodOptional<z.ZodObject<{
|
|
2131
|
+
output_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2132
|
+
input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2133
|
+
cached_input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2134
|
+
reasoning_output_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2135
|
+
active_time_ms: z.ZodOptional<z.ZodNumber>;
|
|
2136
|
+
active_intervals: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
2137
|
+
start: z.ZodString;
|
|
2138
|
+
end: z.ZodString;
|
|
2139
|
+
}, z.core.$loose>>>;
|
|
2140
|
+
active_gap_cap_ms: z.ZodOptional<z.ZodNumber>;
|
|
2141
|
+
active_time_method: z.ZodOptional<z.ZodString>;
|
|
2142
|
+
machine_active_time_ms: z.ZodOptional<z.ZodNumber>;
|
|
2143
|
+
}, z.core.$loose>>;
|
|
2144
|
+
integrity: z.ZodOptional<z.ZodObject<{
|
|
2145
|
+
head_hash: z.ZodString;
|
|
2146
|
+
event_count: z.ZodNumber;
|
|
2147
|
+
}, z.core.$strict>>;
|
|
2148
|
+
}, z.core.$loose>;
|
|
2149
|
+
}, z.core.$loose>;
|
|
2150
|
+
/** Inferred runtime type for {@link SessionSchema}. */
|
|
2151
|
+
type Session = z.infer<typeof SessionSchema>;
|
|
2073
2152
|
|
|
2074
2153
|
/**
|
|
2075
|
-
*
|
|
2076
|
-
*
|
|
2154
|
+
* Threshold above which a still-`running` session with no `session_ended`
|
|
2155
|
+
* event is flagged suspect.
|
|
2077
2156
|
*
|
|
2078
|
-
*
|
|
2079
|
-
*
|
|
2080
|
-
*
|
|
2081
|
-
* paths) always passes through verbatim — only the tool-generated strings are
|
|
2082
|
-
* localized, which is exactly the split this type exists to keep honest.
|
|
2157
|
+
* 24h: long enough that an active long-running session will not be flagged,
|
|
2158
|
+
* short enough that an abandoned process is surfaced within a working day.
|
|
2159
|
+
* Tunable via CLI option in a later step (continuation backlog #23).
|
|
2083
2160
|
*/
|
|
2084
|
-
|
|
2161
|
+
declare const STUCK_THRESHOLD_MS: number;
|
|
2162
|
+
type SuspectReason = "events_say_ended_but_yaml_running" | "running_no_end_event";
|
|
2163
|
+
type SessionEntry = {
|
|
2164
|
+
sessionId: string;
|
|
2165
|
+
session: Session;
|
|
2166
|
+
suspect: boolean;
|
|
2167
|
+
suspectReason: SuspectReason | null;
|
|
2168
|
+
/**
|
|
2169
|
+
* The trail store this entry was read from. Its `sessions` directory locates
|
|
2170
|
+
* the session's `events.jsonl`, so a federated caller can replay events from
|
|
2171
|
+
* the store the session actually lives in (not the local store). For a plain
|
|
2172
|
+
* local load this is the `paths` passed to {@link loadSessionEntries}.
|
|
2173
|
+
*/
|
|
2174
|
+
sourceRoot: BasouPaths;
|
|
2175
|
+
/**
|
|
2176
|
+
* Federation host label from the registry (`~/.basou/hosts.yaml`), or `null`
|
|
2177
|
+
* for the local store. Surfaced by orientation so a merged, multi-host view
|
|
2178
|
+
* can attribute the latest session / decision / next-step to its host.
|
|
2179
|
+
*/
|
|
2180
|
+
host: string | null;
|
|
2181
|
+
};
|
|
2085
2182
|
/**
|
|
2086
|
-
*
|
|
2087
|
-
* the language of its ANCHOR repo (the `repos[]` entry whose path is `.`).
|
|
2183
|
+
* Per-session degradation reason emitted by {@link loadSessionEntries.onSkip}.
|
|
2088
2184
|
*
|
|
2089
|
-
*
|
|
2090
|
-
*
|
|
2091
|
-
* -
|
|
2092
|
-
*
|
|
2093
|
-
*
|
|
2094
|
-
*
|
|
2185
|
+
* - `session_yaml_missing` (ENOENT) and `session_yaml_invalid` (parse or schema
|
|
2186
|
+
* failure) both omit the entry from the result.
|
|
2187
|
+
* - `events_jsonl_unreadable` still pushes the entry with `suspect=false` so
|
|
2188
|
+
* the session row remains visible to the caller; only the suspect check is
|
|
2189
|
+
* degraded. Matches the existing CLI behaviour at
|
|
2190
|
+
* `packages/cli/src/commands/session.ts` (suspect-check stderr warning).
|
|
2191
|
+
*/
|
|
2192
|
+
type SessionSkipReason = "session_yaml_missing" | "session_yaml_invalid" | "events_jsonl_unreadable";
|
|
2193
|
+
type LoadSessionEntriesOptions = {
|
|
2194
|
+
/**
|
|
2195
|
+
* Single `now` shared across every {@link classifySuspect} call so that
|
|
2196
|
+
* sessions classified back-to-back observe the same instant. Avoids
|
|
2197
|
+
* boundary races where a session at age ≈ 24h would flip between calls.
|
|
2198
|
+
*/
|
|
2199
|
+
now: Date;
|
|
2200
|
+
onWarning?: (warning: ReplayWarning, sessionId: string) => void;
|
|
2201
|
+
onSkip?: (sessionId: string, reason: SessionSkipReason) => void;
|
|
2202
|
+
};
|
|
2203
|
+
/**
|
|
2204
|
+
* A trail store to read in a federated load, tagged with its host label.
|
|
2205
|
+
* `host: null` denotes the local store; a non-null label comes from the host
|
|
2206
|
+
* registry (`~/.basou/hosts.yaml`). `paths` is where that store is reachable
|
|
2207
|
+
* as a local path on this machine (an SSHFS mount, an rsync mirror, etc.) —
|
|
2208
|
+
* basou itself never performs any network I/O to obtain it.
|
|
2209
|
+
*/
|
|
2210
|
+
type FederatedRoot = {
|
|
2211
|
+
paths: BasouPaths;
|
|
2212
|
+
host: string | null;
|
|
2213
|
+
};
|
|
2214
|
+
type LoadFederatedOptions = LoadSessionEntriesOptions & {
|
|
2215
|
+
/**
|
|
2216
|
+
* Called when a NON-local root cannot be enumerated (present-but-unreadable
|
|
2217
|
+
* mount, permission error). That root is skipped best-effort so the local
|
|
2218
|
+
* store and other roots still load. The local root (`host: null`) is never
|
|
2219
|
+
* degraded here — its errors propagate, preserving single-store behaviour.
|
|
2220
|
+
* (An absent root path is not an error: {@link enumerateSessionDirs} returns
|
|
2221
|
+
* `[]` on ENOENT, so a dropped mount is simply an empty host.)
|
|
2222
|
+
*/
|
|
2223
|
+
onRootUnavailable?: (host: string, error: unknown) => void;
|
|
2224
|
+
};
|
|
2225
|
+
/**
|
|
2226
|
+
* List session directory names under `paths.sessions`, ULID ascending.
|
|
2095
2227
|
*
|
|
2096
|
-
*
|
|
2097
|
-
*
|
|
2098
|
-
*
|
|
2099
|
-
*
|
|
2228
|
+
* - Returns `[]` when the sessions directory does not exist (empty workspace
|
|
2229
|
+
* or pre-init state).
|
|
2230
|
+
* - Throws `Error("Failed to enumerate sessions", { cause })` on other I/O.
|
|
2231
|
+
* - Only directories are returned (`.gitkeep` and other files are filtered).
|
|
2232
|
+
*
|
|
2233
|
+
* Sort order is `Array.prototype.sort()` default (Unicode code-point
|
|
2234
|
+
* compare). ULIDs are Crockford base32 in uppercase, so the natural sort
|
|
2235
|
+
* is also chronological session-start order.
|
|
2100
2236
|
*/
|
|
2101
|
-
declare function
|
|
2237
|
+
declare function enumerateSessionDirs(paths: BasouPaths): Promise<string[]>;
|
|
2102
2238
|
/**
|
|
2103
|
-
*
|
|
2104
|
-
*
|
|
2105
|
-
*
|
|
2106
|
-
*
|
|
2239
|
+
* Read and validate `<paths.sessions>/<sessionId>/session.yaml`.
|
|
2240
|
+
*
|
|
2241
|
+
* - Re-throws the yaml-store fixed-message `"YAML file not found"` for
|
|
2242
|
+
* ENOENT so the caller can branch on it.
|
|
2243
|
+
* - Throws `Error("Failed to read session.yaml", { cause })` for parse
|
|
2244
|
+
* failures and schema violations (cause is either the YAML parser error
|
|
2245
|
+
* or the zod error).
|
|
2107
2246
|
*/
|
|
2108
|
-
declare function
|
|
2247
|
+
declare function readSessionYaml(paths: BasouPaths, sessionId: string): Promise<Session>;
|
|
2109
2248
|
/**
|
|
2110
|
-
*
|
|
2111
|
-
*
|
|
2112
|
-
*
|
|
2113
|
-
*
|
|
2249
|
+
* Apply a terminal-status mutation to a live session's `session.yaml` AND, in
|
|
2250
|
+
* the same locked write, stamp the tamper-evidence head anchor derived from the
|
|
2251
|
+
* on-disk `events.jsonl` tail. Used by the `exec` / `run` orchestrators for
|
|
2252
|
+
* BOTH terminal writers (the normal end-of-run finalize and the spawn-failure
|
|
2253
|
+
* `failed` finalize).
|
|
2114
2254
|
*
|
|
2115
|
-
*
|
|
2116
|
-
*
|
|
2117
|
-
*
|
|
2118
|
-
*
|
|
2119
|
-
*
|
|
2255
|
+
* Why locked + anchor-from-tail: live appends chain the LOG only and leave the
|
|
2256
|
+
* anchor for finalize. Reading the final tail under the session lock means a
|
|
2257
|
+
* foreign line appended just before finalize (e.g. a `decision record` attached
|
|
2258
|
+
* to a still-running session) is included in the anchor, and a foreign attach
|
|
2259
|
+
* that arrives after the terminal status is set is rejected by the attach gate
|
|
2260
|
+
* — so the anchor can never disagree with the at-rest log. The whole-document
|
|
2261
|
+
* read-modify-write also preserves any field a foreign locked writer set (e.g.
|
|
2262
|
+
* a task attach's `task_id`).
|
|
2263
|
+
*
|
|
2264
|
+
* The anchor is written only when the log is actually chained with at least one
|
|
2265
|
+
* line; a legacy unchained session (and an empty log) is left with no
|
|
2266
|
+
* `integrity` anchor, matching the import writers. The mutator receives the
|
|
2267
|
+
* full {@link Session} document and typically sets
|
|
2268
|
+
* `session.session.status` / `ended_at` / `invocation.exit_code` /
|
|
2269
|
+
* `related_files`.
|
|
2270
|
+
*
|
|
2271
|
+
* Throws the {@link inspectChainTail} errors (torn / mixed log), the
|
|
2272
|
+
* {@link readSessionYaml} errors, a zod error if the mutation produces an
|
|
2273
|
+
* invalid document, or `Error("Failed to overwrite YAML file")` on a disk
|
|
2274
|
+
* failure.
|
|
2120
2275
|
*/
|
|
2121
|
-
|
|
2122
|
-
/** Localized relative age for prose lines, e.g. "3日4時間前" / "3d 4h ago". */
|
|
2123
|
-
relativeAge: (startedAt: string | null, now: Date) => string;
|
|
2124
|
-
common: {
|
|
2125
|
-
/** "最終 session" — the latest live session pointer. */
|
|
2126
|
-
lastSessionLabel: string;
|
|
2127
|
-
/** "直近の判断" — the latest recorded decision pointer. */
|
|
2128
|
-
latestDecisionLabel: string;
|
|
2129
|
-
/** "直近の変更ファイル" — the latest session's related files. */
|
|
2130
|
-
recentFilesLabel: string;
|
|
2131
|
-
/** "理由" — a track's rationale label. */
|
|
2132
|
-
trackWhyLabel: string;
|
|
2133
|
-
/** Note that the latest decision comes from a different session. */
|
|
2134
|
-
decisionOtherSessionNote: (shortSessionId: string) => string;
|
|
2135
|
-
};
|
|
2136
|
-
orientation: {
|
|
2137
|
-
headingWhere: string;
|
|
2138
|
-
headingRecent: (sessionCount: number) => string;
|
|
2139
|
-
headingInFlight: string;
|
|
2140
|
-
headingForward: string;
|
|
2141
|
-
headingCurrency: string;
|
|
2142
|
-
inFlightTasksHeading: (n: number) => string;
|
|
2143
|
-
/**
|
|
2144
|
-
* Body line under the in-flight-tasks heading when NO task was ever
|
|
2145
|
-
* recorded here. "(none)" states that nothing is pending — a claim about
|
|
2146
|
-
* the work. This one claims only what it can see: that the record is
|
|
2147
|
-
* empty. It says nothing about whether the workspace should use tasks,
|
|
2148
|
-
* and names no command: the renderers report position, and a nudge that
|
|
2149
|
-
* cannot be silenced is noise (see `trackNudge`, which is gated).
|
|
2150
|
-
*/
|
|
2151
|
-
noTasksRecorded: string;
|
|
2152
|
-
pendingApprovalsHeading: (n: number) => string;
|
|
2153
|
-
suspectSessionsHeading: (n: number) => string;
|
|
2154
|
-
openTracksHeading: (n: number) => string;
|
|
2155
|
-
/** Stale-decision honesty note under 直近の判断. */
|
|
2156
|
-
decisionStaleNote: (activityAge: string) => string;
|
|
2157
|
-
outOfRootWarning: (count: number, files: string) => string;
|
|
2158
|
-
recentEmpty: string;
|
|
2159
|
-
recentDecisionsLabel: string;
|
|
2160
|
-
recentNextStepLabel: string;
|
|
2161
|
-
recentChangedLabel: string;
|
|
2162
|
-
/** Trails the recent-files line when scratch paths were left out of it. */
|
|
2163
|
-
scratchOmitted: (count: number) => string;
|
|
2164
|
-
trackCloseInstruction: string;
|
|
2165
|
-
nextStepRecordedLabel: (age: string) => string;
|
|
2166
|
-
noteStaleNote: (activityAge: string) => string;
|
|
2167
|
-
fallbackStaleDirection: string;
|
|
2168
|
-
fallbackStaleReferenceLabel: string;
|
|
2169
|
-
trackNudge: string;
|
|
2170
|
-
federatedFreshnessNote: string;
|
|
2171
|
-
bannerUnverifiable: (n: number) => string;
|
|
2172
|
-
bannerStale: (parts: string) => string;
|
|
2173
|
-
partNew: (n: number) => string;
|
|
2174
|
-
partUpdated: (n: number) => string;
|
|
2175
|
-
partsJoiner: string;
|
|
2176
|
-
verdictUnverifiable: (n: number) => [string, string];
|
|
2177
|
-
verdictStale: (parts: string) => [string, string];
|
|
2178
|
-
verdictUpdatedOnly: (n: number) => [string, string];
|
|
2179
|
-
verdictSuspectsAlso: (n: number) => string;
|
|
2180
|
-
verdictEmpty: [string, string];
|
|
2181
|
-
verdictUnprobed: (rel: string, tool: string) => [string, string];
|
|
2182
|
-
verdictCurrent: (rel: string, tool: string, hasHosts: boolean) => string;
|
|
2183
|
-
verdictSuspectsCaveat: (n: number) => string;
|
|
2184
|
-
verdictScopeDisclaimer: string;
|
|
2185
|
-
toolTerminal: string;
|
|
2186
|
-
toolHuman: string;
|
|
2187
|
-
toolImport: string;
|
|
2188
|
-
toolUnknown: string;
|
|
2189
|
-
};
|
|
2190
|
-
handoff: {
|
|
2191
|
-
headingCurrentState: string;
|
|
2192
|
-
headingRecentFiles: string;
|
|
2193
|
-
headingLatestDecision: string;
|
|
2194
|
-
headingOpenTracks: string;
|
|
2195
|
-
headingUnresolved: string;
|
|
2196
|
-
headingReadNext: string;
|
|
2197
|
-
headingNextWork: string;
|
|
2198
|
-
headingSessions: string;
|
|
2199
|
-
lastTaskLabel: string;
|
|
2200
|
-
/** "Work to do next" placeholder: tasks exist, none are open. */
|
|
2201
|
-
noPendingTasks: string;
|
|
2202
|
-
/** "Work to do next" placeholder: no task was ever recorded. */
|
|
2203
|
-
noTasksRecorded: string;
|
|
2204
|
-
decisionStaleNote: string;
|
|
2205
|
-
trackCloseInstruction: string;
|
|
2206
|
-
};
|
|
2207
|
-
decisions: {
|
|
2208
|
-
dateLabel: string;
|
|
2209
|
-
trackKindLine: string;
|
|
2210
|
-
decisionLabel: string;
|
|
2211
|
-
};
|
|
2212
|
-
report: {
|
|
2213
|
-
headingSummary: string;
|
|
2214
|
-
headingVolume: string;
|
|
2215
|
-
headingDecisions: string;
|
|
2216
|
-
headingApprovals: string;
|
|
2217
|
-
headingTasks: string;
|
|
2218
|
-
headingChangedFiles: string;
|
|
2219
|
-
headingSessions: string;
|
|
2220
|
-
headingIntegrity: string;
|
|
2221
|
-
};
|
|
2222
|
-
};
|
|
2223
|
-
/** Look up the string table for a resolved view language. */
|
|
2224
|
-
declare function viewStrings(language: ViewLanguage): ViewStrings;
|
|
2276
|
+
declare function finalizeSessionYaml(paths: BasouPaths, sessionId: string, mutate: (session: Session) => void): Promise<void>;
|
|
2225
2277
|
/**
|
|
2226
|
-
*
|
|
2227
|
-
*
|
|
2228
|
-
*
|
|
2229
|
-
*
|
|
2230
|
-
*
|
|
2231
|
-
*
|
|
2278
|
+
* Classify a `running` session as suspect using one of two rules:
|
|
2279
|
+
*
|
|
2280
|
+
* - Rule A (`events_say_ended_but_yaml_running`): events.jsonl contains a
|
|
2281
|
+
* `session_ended` event but the session.yaml is still `running`. The
|
|
2282
|
+
* session ended cleanly in the event log but the YAML write was lost or
|
|
2283
|
+
* never reached.
|
|
2284
|
+
* - Rule B (`running_no_end_event`): no `session_ended` event and the last
|
|
2285
|
+
* event is older than {@link STUCK_THRESHOLD_MS}. The process likely
|
|
2286
|
+
* crashed or was killed.
|
|
2287
|
+
*
|
|
2288
|
+
* Sessions that are not `running` are never suspect.
|
|
2289
|
+
*
|
|
2290
|
+
* I/O failure on events.jsonl is re-thrown unwrapped so the caller can
|
|
2291
|
+
* degrade with a warning instead of treating the session as healthy. The
|
|
2292
|
+
* caller is also responsible for surfacing replay warnings via `onWarning`.
|
|
2232
2293
|
*/
|
|
2233
|
-
declare function
|
|
2294
|
+
declare function classifySuspect(paths: BasouPaths, sessionId: string, session: Session, now: Date, onWarning?: (warning: ReplayWarning) => void): Promise<{
|
|
2295
|
+
suspect: boolean;
|
|
2296
|
+
suspectReason: SuspectReason | null;
|
|
2297
|
+
}>;
|
|
2298
|
+
declare function loadSessionEntries(paths: BasouPaths, options: LoadSessionEntriesOptions): Promise<SessionEntry[]>;
|
|
2234
2299
|
/**
|
|
2235
|
-
*
|
|
2236
|
-
*
|
|
2237
|
-
*
|
|
2238
|
-
*
|
|
2239
|
-
*
|
|
2240
|
-
*
|
|
2241
|
-
*
|
|
2242
|
-
*
|
|
2243
|
-
* {@link resolveViewLanguage} keys on the manifest path being `.`, while the
|
|
2244
|
-
* instruction-file callers flag the anchor by resolved-path identity. For a
|
|
2245
|
-
* conventional manifest (anchor declared as `.`) the two agree; a roster that
|
|
2246
|
-
* reaches the anchor only through an aliased path is where they can diverge,
|
|
2247
|
-
* and the caller's flag is authoritative for the instruction files.
|
|
2300
|
+
* Federated load across multiple trail stores. Each root's sessions are tagged
|
|
2301
|
+
* with that root's host label and `sourceRoot`, so a caller replays events from
|
|
2302
|
+
* the store the session lives in. De-duped by `sessionId` (a per-host random
|
|
2303
|
+
* ULID), then by `source.external_id` when present — first occurrence wins, so
|
|
2304
|
+
* pass the local root FIRST to keep it authoritative (e.g. over a re-imported
|
|
2305
|
+
* copy of the same vendor session on another host). A non-local root that
|
|
2306
|
+
* cannot be enumerated is reported via `onRootUnavailable` and skipped; the
|
|
2307
|
+
* local root's errors propagate, matching {@link loadSessionEntries}.
|
|
2248
2308
|
*/
|
|
2249
|
-
declare function
|
|
2250
|
-
|
|
2251
|
-
language?: RepoLanguage | undefined;
|
|
2252
|
-
}>): ViewLanguage;
|
|
2309
|
+
declare function loadFederatedSessionEntries(roots: ReadonlyArray<FederatedRoot>, options: LoadFederatedOptions): Promise<SessionEntry[]>;
|
|
2310
|
+
|
|
2253
2311
|
/**
|
|
2254
|
-
*
|
|
2255
|
-
*
|
|
2256
|
-
*
|
|
2257
|
-
*
|
|
2258
|
-
*
|
|
2259
|
-
*
|
|
2312
|
+
* Decision-gap surfacer: which recorded decisions are still waiting for someone.
|
|
2313
|
+
*
|
|
2314
|
+
* The rule it applies, stated by the report that motivated it: a decision that
|
|
2315
|
+
* changes what gets built should have a task carrying it, and the ones with no
|
|
2316
|
+
* task are listed. It reads only captured provenance and writes nothing.
|
|
2317
|
+
*
|
|
2318
|
+
* The question is a RELATION — "is any task carrying this decision" — and the
|
|
2319
|
+
* text scan below is only today's way of answering it. Stating it that way is
|
|
2320
|
+
* deliberate: when `task_created` grows a field naming the decision it serves,
|
|
2321
|
+
* honouring that field answers the same question better and is an
|
|
2322
|
+
* implementation change, where redefining the question would not be.
|
|
2323
|
+
*
|
|
2324
|
+
* Two properties are load-bearing:
|
|
2325
|
+
*
|
|
2326
|
+
* - Nothing here reads what a decision MEANS, so the answer does not depend on
|
|
2327
|
+
* a model and does not change between runs over the same store.
|
|
2328
|
+
* - The default is fail-closed: a decision with no task is listed. An opt-in
|
|
2329
|
+
* mark ("this one produces work") was rejected upstream because forgetting
|
|
2330
|
+
* the mark is the same failure the report exists to catch.
|
|
2331
|
+
*
|
|
2332
|
+
* Fail-closed only pays for itself if the list is drainable, so the population
|
|
2333
|
+
* is cut on four structural grounds — a timestamp, a `source`, a `kind`, and a
|
|
2334
|
+
* void. None requires reading meaning, and each is reported as a count so the
|
|
2335
|
+
* cut is never silent:
|
|
2336
|
+
*
|
|
2337
|
+
* - {@link DECISION_GAPS_EPOCH}: decisions predating this feature are out of
|
|
2338
|
+
* scope. Applying the rule to a whole history measured ~1450 entries on the
|
|
2339
|
+
* store it was built against, which buries the signal on day one.
|
|
2340
|
+
* - {@link LOCAL_CLI_EVENT_SOURCE}: only decisions somebody recorded by
|
|
2341
|
+
* running basou (`basou decision capture` or `basou decision record`), as
|
|
2342
|
+
* opposed to ones a reader derived. An importer derives decisions from a
|
|
2343
|
+
* transcript's in-conversation questions ("how far should I implement? ->
|
|
2344
|
+
* findings 1 and 3"), which were 70% of that store's decisions and 0 of the
|
|
2345
|
+
* ones any task carried. Those are answers given while working, not plans
|
|
2346
|
+
* anybody ratified.
|
|
2347
|
+
* - `kind: "track"`: a track is ALREADY resurfaced, every session, until it is
|
|
2348
|
+
* voided — orientation and handoff both carry it under "open tracks". For a
|
|
2349
|
+
* track the premise "recorded, then never surfaced again" is false by
|
|
2350
|
+
* construction, so listing it here says nothing the reader is not already
|
|
2351
|
+
* shown, and it measured 27-45% of the list.
|
|
2352
|
+
* - voided: `basou decision void` is the closing verb this product tells the
|
|
2353
|
+
* operator to use, and a direction no longer in force is not waiting for
|
|
2354
|
+
* anyone. Honouring it everywhere gives the operator ONE verb that closes;
|
|
2355
|
+
* refusing it here would leave a list drainable only by writing a sham task.
|
|
2356
|
+
*
|
|
2357
|
+
* What it will not do is decide a decision's fate on anything it cannot check.
|
|
2358
|
+
* A task naming an id that no decision in the store has does NOT count as
|
|
2359
|
+
* carrying it, and a store it could only partly read says so rather than
|
|
2360
|
+
* reporting a clean answer over the part it managed.
|
|
2361
|
+
*/
|
|
2362
|
+
/**
|
|
2363
|
+
* Start of the population: decisions recorded before this instant are out of
|
|
2364
|
+
* scope, whatever else is true of them.
|
|
2365
|
+
*
|
|
2366
|
+
* A fixed constant rather than per-workspace state, so every workspace answers
|
|
2367
|
+
* the same question and nothing has to be initialised or migrated. The value is
|
|
2368
|
+
* the instant this was written; a release landing later, or a workspace first
|
|
2369
|
+
* running it later, only means that run starts with the decisions recorded in
|
|
2370
|
+
* between, and {@link DecisionGapsSummary.scope} reports the boundary on every
|
|
2371
|
+
* run so the head start is never silent. `--since` overrides it.
|
|
2372
|
+
*/
|
|
2373
|
+
declare const DECISION_GAPS_EPOCH = "2026-09-18T12:00:00.000Z";
|
|
2374
|
+
/** A decision in the population that no task carries. */
|
|
2375
|
+
type DecisionGap = {
|
|
2376
|
+
decisionId: string;
|
|
2377
|
+
title: string;
|
|
2378
|
+
recordedAt: string;
|
|
2379
|
+
sessionId: string;
|
|
2380
|
+
};
|
|
2381
|
+
/** The population's boundaries, as the run actually applied them. */
|
|
2382
|
+
type DecisionGapsScope = {
|
|
2383
|
+
/** Decisions recorded before this instant are out of scope. */
|
|
2384
|
+
start: string;
|
|
2385
|
+
/** Only decisions this event source recorded are in scope. */
|
|
2386
|
+
source: string;
|
|
2387
|
+
};
|
|
2388
|
+
/**
|
|
2389
|
+
* Why decisions left the population, by ground. The grounds are applied in this
|
|
2390
|
+
* order and each decision is counted under the FIRST that excludes it, so these
|
|
2391
|
+
* partition the excluded set.
|
|
2260
2392
|
*/
|
|
2261
|
-
type
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
* (ja -> JA table, everything else -> EN), so the JA table's en / en+ja /
|
|
2271
|
-
* unset branches and the EN table's ja branch are unreachable from
|
|
2272
|
-
* renderPresetBlock — they exist for table completeness (and the
|
|
2273
|
-
* both-language sweep test), not because a render can emit them.
|
|
2274
|
-
*/
|
|
2275
|
-
sourceLanguageLabel: (l: RepoLanguage | undefined) => string;
|
|
2276
|
-
/** Published-surface kind. */
|
|
2277
|
-
publishKindLabel: (k: PublishTarget["kind"]) => string;
|
|
2278
|
-
/** A published surface's visibility (independent of the source repo's). */
|
|
2279
|
-
publishVisibilityLabel: (v: RepoVisibility | undefined) => string;
|
|
2280
|
-
/** A published surface's content language (read by end users; may differ from source). */
|
|
2281
|
-
contentLanguageLabel: (l: RepoLanguage | undefined) => string;
|
|
2282
|
-
/** "ソース可視性" — the source-visibility line label. */
|
|
2283
|
-
sourceVisibilityLabel: string;
|
|
2284
|
-
/** "ソース言語" — the source-language line label. */
|
|
2285
|
-
sourceLanguageLineLabel: string;
|
|
2286
|
-
/** "- 配信物: なし" — no published surfaces. */
|
|
2287
|
-
publishesNone: string;
|
|
2288
|
-
/** "- 配信物:" — the published-surfaces list header. */
|
|
2289
|
-
publishesHeader: string;
|
|
2290
|
-
};
|
|
2291
|
-
viewBlock: {
|
|
2292
|
-
heading: string;
|
|
2293
|
-
intro: string;
|
|
2294
|
-
selfNote: (viewName: string) => string;
|
|
2295
|
-
aggregates: (repoCount: number) => string;
|
|
2296
|
-
reposHeading: string;
|
|
2297
|
-
tableHeader: string;
|
|
2298
|
-
/** Instruction-file ownership labels: who writes the repo's AGENTS.md. */
|
|
2299
|
-
instructionsAnchor: string;
|
|
2300
|
-
instructionsSelf: string;
|
|
2301
|
-
instructionsHub: string;
|
|
2302
|
-
/** "未設定" — the short table cell for an undeclared visibility / language. */
|
|
2303
|
-
unsetShort: string;
|
|
2304
|
-
commitHeading: string;
|
|
2305
|
-
commitBody: string;
|
|
2306
|
-
conventionsHeading: string;
|
|
2307
|
-
conventionsBody: string;
|
|
2308
|
-
principlesHeading: string;
|
|
2309
|
-
principleStateless: string;
|
|
2310
|
-
principleNoFiles: string;
|
|
2311
|
-
};
|
|
2312
|
-
anchorStarter: {
|
|
2313
|
-
identityLine: (title: string) => string;
|
|
2314
|
-
starterNote: string;
|
|
2315
|
-
basicsHeading: string;
|
|
2316
|
-
basicsTodo: string;
|
|
2317
|
-
commitHeading: string;
|
|
2318
|
-
commitPlanning: string;
|
|
2319
|
-
commitImplementation: string;
|
|
2320
|
-
commitView: string;
|
|
2321
|
-
conventionsHeading: string;
|
|
2322
|
-
conventionsBody: string;
|
|
2323
|
-
viewPointerLine: (viewName: string) => string;
|
|
2324
|
-
policyHeading: string;
|
|
2325
|
-
policyTodo: string[];
|
|
2326
|
-
};
|
|
2393
|
+
type DecisionGapsExcluded = {
|
|
2394
|
+
/** Recorded before {@link DecisionGapsScope.start}. */
|
|
2395
|
+
byStart: number;
|
|
2396
|
+
/** Recorded by something other than {@link DecisionGapsScope.source}. */
|
|
2397
|
+
bySource: number;
|
|
2398
|
+
/** `kind: "track"` — already resurfaced every session until closed. */
|
|
2399
|
+
track: number;
|
|
2400
|
+
/** Closed with `basou decision void`. */
|
|
2401
|
+
voided: number;
|
|
2327
2402
|
};
|
|
2328
|
-
/** Look up the instruction-file string table for a resolved content language. */
|
|
2329
|
-
declare function presetStrings(language: ViewLanguage): PresetStrings;
|
|
2330
|
-
|
|
2331
|
-
/** Session lifecycle states. */
|
|
2332
|
-
declare const SessionStatusSchema: z.ZodEnum<{
|
|
2333
|
-
initialized: "initialized";
|
|
2334
|
-
running: "running";
|
|
2335
|
-
waiting_approval: "waiting_approval";
|
|
2336
|
-
completed: "completed";
|
|
2337
|
-
failed: "failed";
|
|
2338
|
-
interrupted: "interrupted";
|
|
2339
|
-
imported: "imported";
|
|
2340
|
-
archived: "archived";
|
|
2341
|
-
}>;
|
|
2342
|
-
/** Inferred runtime type for {@link SessionStatusSchema}. */
|
|
2343
|
-
type SessionStatus = z.infer<typeof SessionStatusSchema>;
|
|
2344
2403
|
/**
|
|
2345
|
-
*
|
|
2404
|
+
* What the run could not read. Every field here can only make {@link
|
|
2405
|
+
* DecisionGapsSummary.gaps} wrong in a way the reader cannot see, so a non-zero
|
|
2406
|
+
* count is reported rather than absorbed.
|
|
2407
|
+
*/
|
|
2408
|
+
type DecisionGapsIncomplete = {
|
|
2409
|
+
/**
|
|
2410
|
+
* Sessions this run could not read in full — a `session.yaml` that is missing
|
|
2411
|
+
* or does not validate, or an event log that failed to read.
|
|
2412
|
+
*
|
|
2413
|
+
* What was lost is not knowable from here: a log that fails partway through
|
|
2414
|
+
* has already yielded some events, so a session counted here may have
|
|
2415
|
+
* contributed everything, nothing, or part of what it holds. A decision of
|
|
2416
|
+
* theirs can therefore be missing from every count, and a void of theirs may
|
|
2417
|
+
* not have closed what it closes — so both a missing row and a wrongly
|
|
2418
|
+
* present one are possible.
|
|
2419
|
+
*/
|
|
2420
|
+
sessions: number;
|
|
2421
|
+
/** Task files that could not be read, so any decision they carry looks uncarried. */
|
|
2422
|
+
tasks: number;
|
|
2423
|
+
/**
|
|
2424
|
+
* Ids named by a task that no decision in the store has. Counted, and
|
|
2425
|
+
* deliberately NOT treated as carrying anything: a string nobody recorded
|
|
2426
|
+
* must not be able to take a decision off this list.
|
|
2427
|
+
*/
|
|
2428
|
+
unknownReferences: number;
|
|
2429
|
+
};
|
|
2430
|
+
type DecisionGapsSummary = {
|
|
2431
|
+
generatedAt: string;
|
|
2432
|
+
scope: DecisionGapsScope;
|
|
2433
|
+
/** Decisions with no task carrying them, newest first. Capped by `limit`. */
|
|
2434
|
+
gaps: DecisionGap[];
|
|
2435
|
+
/** Entries omitted from `gaps` by `limit`; 0 when nothing was cut. */
|
|
2436
|
+
truncated: number;
|
|
2437
|
+
/** Population members some task carries. */
|
|
2438
|
+
carried: number;
|
|
2439
|
+
/** `gaps.length + truncated + carried`. */
|
|
2440
|
+
populationCount: number;
|
|
2441
|
+
excluded: DecisionGapsExcluded;
|
|
2442
|
+
incomplete: DecisionGapsIncomplete;
|
|
2443
|
+
/** Task files read (live and archived). */
|
|
2444
|
+
tasksScanned: number;
|
|
2445
|
+
};
|
|
2446
|
+
type DecisionGapsInput = {
|
|
2447
|
+
paths: BasouPaths;
|
|
2448
|
+
nowIso: string;
|
|
2449
|
+
/** Defaults to {@link DECISION_GAPS_EPOCH}. */
|
|
2450
|
+
start?: string;
|
|
2451
|
+
/**
|
|
2452
|
+
* Maximum entries in `gaps`; the rest are counted in `truncated`. `0` yields
|
|
2453
|
+
* an empty `gaps` with everything in `truncated` — it is a cap of zero, not
|
|
2454
|
+
* "uncapped". Omit the field for uncapped. (The CLI's `--limit 0` means
|
|
2455
|
+
* uncapped and omits this.)
|
|
2456
|
+
*/
|
|
2457
|
+
limit?: number;
|
|
2458
|
+
onWarning?: (warning: ReplayWarning, sessionId: string) => void;
|
|
2459
|
+
onSessionSkip?: (sessionId: string, reason: SessionSkipReason) => void;
|
|
2460
|
+
};
|
|
2461
|
+
/**
|
|
2462
|
+
* Find decisions in the population that no task carries.
|
|
2346
2463
|
*
|
|
2347
|
-
*
|
|
2348
|
-
*
|
|
2349
|
-
* transcript (`~/.claude/projects/*.jsonl`) by `basou import claude-code`.
|
|
2350
|
-
* - `codex-adapter` — a live `basou run codex` process wrap.
|
|
2351
|
-
* - `codex-import` — derived after the fact from an OpenAI Codex native
|
|
2352
|
-
* rollout log (date-partitioned `~/.codex/sessions`) by `basou import codex`.
|
|
2353
|
-
* - `import` — a round-trip of a Basou-format export (`basou session import`).
|
|
2354
|
-
* - `human` / `terminal` — manually-authored / terminal-recorded sessions.
|
|
2464
|
+
* Ordering is `recordedAt` descending with the decision id (a ULID, so
|
|
2465
|
+
* monotonic) as tie-breaker, giving a stable newest-first list.
|
|
2355
2466
|
*/
|
|
2356
|
-
declare
|
|
2357
|
-
|
|
2358
|
-
import: "import";
|
|
2359
|
-
"claude-code-import": "claude-code-import";
|
|
2360
|
-
"codex-adapter": "codex-adapter";
|
|
2361
|
-
"codex-import": "codex-import";
|
|
2362
|
-
human: "human";
|
|
2363
|
-
terminal: "terminal";
|
|
2364
|
-
}>;
|
|
2365
|
-
/** Inferred runtime type for {@link SessionSourceKindSchema}. */
|
|
2366
|
-
type SessionSourceKind = z.infer<typeof SessionSourceKindSchema>;
|
|
2467
|
+
declare function findDecisionGaps(input: DecisionGapsInput): Promise<DecisionGapsSummary>;
|
|
2468
|
+
|
|
2367
2469
|
/**
|
|
2368
|
-
*
|
|
2369
|
-
*
|
|
2470
|
+
* Project roster drift (the "saddle" model). A project's repos are DECLARED
|
|
2471
|
+
* once in the manifest's `repos` list; the capture config (`source_roots`) must
|
|
2472
|
+
* cover every declared repo. This computes the drift between the two so
|
|
2473
|
+
* `basou project check` can surface a declared repo that is NOT being captured
|
|
2474
|
+
* — the class of bug where a companion repo was wired into the workspace but
|
|
2475
|
+
* never added to `source_roots`, so its work silently fell out of capture.
|
|
2370
2476
|
*
|
|
2371
|
-
*
|
|
2372
|
-
*
|
|
2373
|
-
*
|
|
2374
|
-
* - Engaged-time metrics (`active_*`): the billing-oriented active time derived
|
|
2375
|
-
* from the session's genuine engagement timestamps (conversation turns plus
|
|
2376
|
-
* action events), with idle gaps capped. `active_intervals` are the merged
|
|
2377
|
-
* wall-clock ranges (so cross-session totals can de-duplicate overlapping
|
|
2378
|
-
* work by interval union); `active_time_ms` is their summed duration;
|
|
2379
|
-
* `active_gap_cap_ms` and `active_time_method` lock the methodology so the
|
|
2380
|
-
* stored numbers stay interpretable if the method changes later. When a
|
|
2381
|
-
* source records explicit per-turn intervals (Codex), `active_time_method` is
|
|
2382
|
-
* `turn-intervals` and the in-turn time is the log's real wall-clock span
|
|
2383
|
-
* rather than a gap-capped approximation; the active semantics are unchanged.
|
|
2384
|
-
* - `machine_active_time_ms`: model compute time — the summed duration of the
|
|
2385
|
-
* source's per-turn spans (Codex `task_complete.duration_ms`), a SUBSET of a
|
|
2386
|
-
* single session's engaged active time. Unlike `active_intervals` it is a
|
|
2387
|
-
* plain sum, NOT wall-clock-deduplicated, so two concurrent sessions can sum
|
|
2388
|
-
* past their billable (union) active wall-clock — that is intended (two models
|
|
2389
|
-
* working at once did two machine-hours in one wall-clock hour). Captured only
|
|
2390
|
-
* for sources that record per-turn duration (Codex); absent otherwise.
|
|
2391
|
-
*
|
|
2392
|
-
* Absent on sessions imported before a given field existed (re-import to
|
|
2393
|
-
* backfill). Live sessions carry no engaged-time metrics and fall back to
|
|
2394
|
-
* event-derived active time at stats time.
|
|
2477
|
+
* Pure: it compares declared relative paths against captured relative paths and
|
|
2478
|
+
* performs no filesystem or git I/O. Paths are compared as declared (both lists
|
|
2479
|
+
* use the same machine-portable relative-path form), not resolved on disk.
|
|
2395
2480
|
*/
|
|
2396
|
-
|
|
2397
|
-
output_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2398
|
-
input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2399
|
-
cached_input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2400
|
-
reasoning_output_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2401
|
-
active_time_ms: z.ZodOptional<z.ZodNumber>;
|
|
2402
|
-
active_intervals: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
2403
|
-
start: z.ZodString;
|
|
2404
|
-
end: z.ZodString;
|
|
2405
|
-
}, z.core.$loose>>>;
|
|
2406
|
-
active_gap_cap_ms: z.ZodOptional<z.ZodNumber>;
|
|
2407
|
-
active_time_method: z.ZodOptional<z.ZodString>;
|
|
2408
|
-
machine_active_time_ms: z.ZodOptional<z.ZodNumber>;
|
|
2409
|
-
}, z.core.$loose>;
|
|
2410
|
-
/** Inferred runtime type for {@link SessionMetricsSchema}. */
|
|
2411
|
-
type SessionMetrics = z.infer<typeof SessionMetricsSchema>;
|
|
2481
|
+
type RepoVisibility = "public" | "private" | "future-public";
|
|
2412
2482
|
/**
|
|
2413
|
-
*
|
|
2414
|
-
*
|
|
2415
|
-
*
|
|
2416
|
-
* Written by the import / in-place re-import writers and, for a live session
|
|
2417
|
-
* (`exec` / `run` / ad-hoc), by the finalize once it reaches a terminal status.
|
|
2418
|
-
* Absent on a still-live session (the anchor is stamped at finalize) and on a
|
|
2419
|
-
* pre-feature unchained session. Additive optional => no schema_version bump.
|
|
2420
|
-
* `.strict()` because the writers fully own the shape.
|
|
2483
|
+
* The audience-driven language axis. Independent of visibility: a private repo
|
|
2484
|
+
* can publish English content, a public repo can carry bilingual docs. `en` /
|
|
2485
|
+
* `ja` for a single audience, `en+ja` when both are served.
|
|
2421
2486
|
*/
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
}, z.core.$strict>;
|
|
2426
|
-
/** Inferred runtime type for {@link SessionIntegritySchema}. */
|
|
2427
|
-
type SessionIntegrity = z.infer<typeof SessionIntegritySchema>;
|
|
2487
|
+
type RepoLanguage = "en" | "ja" | "en+ja";
|
|
2488
|
+
/** A published surface a repo emits: a deployed website or a package registry. */
|
|
2489
|
+
type PublishKind = "web" | "npm";
|
|
2428
2490
|
/**
|
|
2429
|
-
*
|
|
2430
|
-
*
|
|
2431
|
-
*
|
|
2491
|
+
* Where a repo's agent instruction files live (the instruction-source axis),
|
|
2492
|
+
* independent of visibility / language / publishes. `hub` is basou's native,
|
|
2493
|
+
* generated hub-and-spoke topology (canonical in the anchor, gitignored symlinks
|
|
2494
|
+
* in each repo); `self` is the additive opt-in where the canonical AGENTS.md is a
|
|
2495
|
+
* regular committed file in the repo itself and basou stays hands-off about its
|
|
2496
|
+
* content. See {@link instructionMode} for the default (absent => `hub`).
|
|
2432
2497
|
*/
|
|
2433
|
-
|
|
2434
|
-
schema_version: z.ZodString;
|
|
2435
|
-
session: z.ZodObject<{
|
|
2436
|
-
id: z.ZodString & z.ZodType<`ses_${string}`, string, z.core.$ZodTypeInternals<`ses_${string}`, string>>;
|
|
2437
|
-
label: z.ZodOptional<z.ZodString>;
|
|
2438
|
-
task_id: z.ZodOptional<z.ZodNullable<z.ZodString & z.ZodType<`task_${string}`, string, z.core.$ZodTypeInternals<`task_${string}`, string>>>>;
|
|
2439
|
-
workspace_id: z.ZodString & z.ZodType<`ws_${string}`, string, z.core.$ZodTypeInternals<`ws_${string}`, string>>;
|
|
2440
|
-
source: z.ZodObject<{
|
|
2441
|
-
kind: z.ZodEnum<{
|
|
2442
|
-
"claude-code-adapter": "claude-code-adapter";
|
|
2443
|
-
import: "import";
|
|
2444
|
-
"claude-code-import": "claude-code-import";
|
|
2445
|
-
"codex-adapter": "codex-adapter";
|
|
2446
|
-
"codex-import": "codex-import";
|
|
2447
|
-
human: "human";
|
|
2448
|
-
terminal: "terminal";
|
|
2449
|
-
}>;
|
|
2450
|
-
version: z.ZodLiteral<"0.1.0">;
|
|
2451
|
-
external_id: z.ZodOptional<z.ZodString>;
|
|
2452
|
-
source_size_bytes: z.ZodOptional<z.ZodNumber>;
|
|
2453
|
-
}, z.core.$loose>;
|
|
2454
|
-
started_at: z.ZodString;
|
|
2455
|
-
ended_at: z.ZodOptional<z.ZodString>;
|
|
2456
|
-
status: z.ZodEnum<{
|
|
2457
|
-
initialized: "initialized";
|
|
2458
|
-
running: "running";
|
|
2459
|
-
waiting_approval: "waiting_approval";
|
|
2460
|
-
completed: "completed";
|
|
2461
|
-
failed: "failed";
|
|
2462
|
-
interrupted: "interrupted";
|
|
2463
|
-
imported: "imported";
|
|
2464
|
-
archived: "archived";
|
|
2465
|
-
}>;
|
|
2466
|
-
working_directory: z.ZodString;
|
|
2467
|
-
invocation: z.ZodObject<{
|
|
2468
|
-
command: z.ZodString;
|
|
2469
|
-
args: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
2470
|
-
exit_code: z.ZodNullable<z.ZodNumber>;
|
|
2471
|
-
}, z.core.$loose>;
|
|
2472
|
-
related_files: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
2473
|
-
events_log: z.ZodDefault<z.ZodString>;
|
|
2474
|
-
summary: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
2475
|
-
metrics: z.ZodOptional<z.ZodObject<{
|
|
2476
|
-
output_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2477
|
-
input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2478
|
-
cached_input_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2479
|
-
reasoning_output_tokens: z.ZodOptional<z.ZodNumber>;
|
|
2480
|
-
active_time_ms: z.ZodOptional<z.ZodNumber>;
|
|
2481
|
-
active_intervals: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
2482
|
-
start: z.ZodString;
|
|
2483
|
-
end: z.ZodString;
|
|
2484
|
-
}, z.core.$loose>>>;
|
|
2485
|
-
active_gap_cap_ms: z.ZodOptional<z.ZodNumber>;
|
|
2486
|
-
active_time_method: z.ZodOptional<z.ZodString>;
|
|
2487
|
-
machine_active_time_ms: z.ZodOptional<z.ZodNumber>;
|
|
2488
|
-
}, z.core.$loose>>;
|
|
2489
|
-
integrity: z.ZodOptional<z.ZodObject<{
|
|
2490
|
-
head_hash: z.ZodString;
|
|
2491
|
-
event_count: z.ZodNumber;
|
|
2492
|
-
}, z.core.$strict>>;
|
|
2493
|
-
}, z.core.$loose>;
|
|
2494
|
-
}, z.core.$loose>;
|
|
2495
|
-
/** Inferred runtime type for {@link SessionSchema}. */
|
|
2496
|
-
type Session = z.infer<typeof SessionSchema>;
|
|
2497
|
-
|
|
2498
|
+
type RepoInstructions = "hub" | "self";
|
|
2498
2499
|
/**
|
|
2499
|
-
*
|
|
2500
|
-
*
|
|
2501
|
-
*
|
|
2502
|
-
*
|
|
2503
|
-
*
|
|
2504
|
-
* Tunable via CLI option in a later step (continuation backlog #23).
|
|
2500
|
+
* One published surface. Its visibility and language are INDEPENDENT of the
|
|
2501
|
+
* source repo's: a private repo commonly publishes a public website. Both are
|
|
2502
|
+
* optional so a surface can be declared
|
|
2503
|
+
* before those facts are pinned down (mirroring how `adopt` leaves repo
|
|
2504
|
+
* visibility unset for the operator to fill in).
|
|
2505
2505
|
*/
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
sourceRoot: BasouPaths;
|
|
2506
|
+
type PublishTarget = {
|
|
2507
|
+
kind: PublishKind;
|
|
2508
|
+
visibility?: RepoVisibility | undefined;
|
|
2509
|
+
language?: RepoLanguage | undefined;
|
|
2510
|
+
};
|
|
2511
|
+
type RepoEntry = {
|
|
2512
|
+
/** Path relative to the manifest repo root (e.g. ".", "../takuhon"). */
|
|
2513
|
+
path: string;
|
|
2514
|
+
visibility?: RepoVisibility | undefined;
|
|
2515
|
+
/** Source language (commits/comments/code, read by contributors). Independent of visibility. */
|
|
2516
|
+
language?: RepoLanguage | undefined;
|
|
2517
|
+
/** Published surfaces this repo emits (opt-in; absent for a repo that publishes nothing). */
|
|
2518
|
+
publishes?: PublishTarget[] | undefined;
|
|
2520
2519
|
/**
|
|
2521
|
-
*
|
|
2522
|
-
*
|
|
2523
|
-
*
|
|
2520
|
+
* Instruction-source mode. Absent => `hub` (basou's native generated topology),
|
|
2521
|
+
* so an existing roster's behavior is unchanged. `self` opts the repo out of
|
|
2522
|
+
* generation: its AGENTS.md is a hand-authored committed file and basou stays
|
|
2523
|
+
* hands-off. Resolve the effective mode with {@link instructionMode}.
|
|
2524
2524
|
*/
|
|
2525
|
-
|
|
2525
|
+
instructions?: RepoInstructions | undefined;
|
|
2526
2526
|
};
|
|
2527
2527
|
/**
|
|
2528
|
-
*
|
|
2529
|
-
*
|
|
2530
|
-
*
|
|
2531
|
-
*
|
|
2532
|
-
*
|
|
2533
|
-
* the session row remains visible to the caller; only the suspect check is
|
|
2534
|
-
* degraded. Matches the existing CLI behaviour at
|
|
2535
|
-
* `packages/cli/src/commands/session.ts` (suspect-check stderr warning).
|
|
2528
|
+
* The effective instruction-source mode for a repo: the declared `instructions`,
|
|
2529
|
+
* defaulting to `hub` when absent. The default is the single guarantee that an
|
|
2530
|
+
* existing roster (which has no `instructions` field) keeps basou's current
|
|
2531
|
+
* hub-and-spoke behavior byte-for-byte — every generator branches on this, never
|
|
2532
|
+
* on the raw optional field, so "absent => hub" is decided in exactly one place.
|
|
2536
2533
|
*/
|
|
2537
|
-
|
|
2538
|
-
|
|
2534
|
+
declare function instructionMode(entry: {
|
|
2535
|
+
instructions?: RepoInstructions | undefined;
|
|
2536
|
+
}): RepoInstructions;
|
|
2537
|
+
type RosterDriftSummary = {
|
|
2538
|
+
declaredCount: number;
|
|
2539
|
+
capturedCount: number;
|
|
2540
|
+
/** Declared in `repos` but absent from `source_roots`: a capture gap. */
|
|
2541
|
+
gaps: RepoEntry[];
|
|
2542
|
+
/** In `source_roots` but not declared in `repos` (e.g. a workspace view, or a stray). */
|
|
2543
|
+
extra: string[];
|
|
2544
|
+
/** Declared paths that are also captured. */
|
|
2545
|
+
matched: string[];
|
|
2546
|
+
/** True when there is no capture gap (every declared repo is covered). */
|
|
2547
|
+
ok: boolean;
|
|
2548
|
+
};
|
|
2549
|
+
/**
|
|
2550
|
+
* Compute the {@link RosterDriftSummary} for a project. A declared repo missing
|
|
2551
|
+
* from the captured set is a `gap` (the surfaced suspicion); a captured path not
|
|
2552
|
+
* in the declared set is `extra` (commonly the workspace view, which is a
|
|
2553
|
+
* capture source but not itself a project repo). With no declared roster, there
|
|
2554
|
+
* are no gaps (nothing to check against) and every captured path is `extra`.
|
|
2555
|
+
*/
|
|
2556
|
+
declare function summarizeRosterDrift(input: {
|
|
2557
|
+
repos?: RepoEntry[];
|
|
2558
|
+
sourceRoots?: string[];
|
|
2559
|
+
}): RosterDriftSummary;
|
|
2560
|
+
type SourceRootsReconcile = {
|
|
2539
2561
|
/**
|
|
2540
|
-
*
|
|
2541
|
-
*
|
|
2542
|
-
*
|
|
2562
|
+
* The reconciled `source_roots`: the existing entries verbatim, then every
|
|
2563
|
+
* declared repo path that was missing (normalized, in roster order). Existing
|
|
2564
|
+
* order and form are preserved so the manifest diff is minimal and reversible.
|
|
2543
2565
|
*/
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2566
|
+
next: string[];
|
|
2567
|
+
/** Declared repo paths (normalized) that were appended because `source_roots` did not cover them. */
|
|
2568
|
+
added: string[];
|
|
2569
|
+
/** True when `source_roots` already covers every declared repo (`next` equals the current list). */
|
|
2570
|
+
unchanged: boolean;
|
|
2547
2571
|
};
|
|
2548
2572
|
/**
|
|
2549
|
-
*
|
|
2550
|
-
*
|
|
2551
|
-
*
|
|
2552
|
-
*
|
|
2553
|
-
*
|
|
2573
|
+
* Derive the `source_roots` a project's declared repo roster requires. The
|
|
2574
|
+
* roster (`repos`) is the single source of truth for which repos belong to the
|
|
2575
|
+
* project; this is the actuator behind `basou project sync`, computing the
|
|
2576
|
+
* additive reconciliation so every declared repo is captured.
|
|
2577
|
+
*
|
|
2578
|
+
* ADDITIVE ONLY: it appends declared paths that are missing and never removes
|
|
2579
|
+
* an existing entry. A captured-but-undeclared path (commonly the generated
|
|
2580
|
+
* workspace view — a legitimate capture source that is not itself a project
|
|
2581
|
+
* repo) is preserved; pruning strays is deferred to the slice that generates
|
|
2582
|
+
* the view (so basou knows which extras it owns). Existing entries are kept
|
|
2583
|
+
* byte-identical; only appended paths are normalized.
|
|
2584
|
+
*
|
|
2585
|
+
* Pure: no filesystem or git I/O. Paths are compared in the same normalized
|
|
2586
|
+
* form as {@link summarizeRosterDrift}, so a trailing-slash variant of an
|
|
2587
|
+
* already-captured repo is not re-appended.
|
|
2554
2588
|
*/
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2589
|
+
declare function reconcileSourceRoots(input: {
|
|
2590
|
+
repos?: RepoEntry[];
|
|
2591
|
+
sourceRoots?: string[];
|
|
2592
|
+
}): SourceRootsReconcile;
|
|
2593
|
+
/**
|
|
2594
|
+
* On-disk classification of a source-root candidate during adoption: a git repo
|
|
2595
|
+
* root (→ becomes a roster entry), a resolved-but-non-repo directory (the
|
|
2596
|
+
* generated workspace view, `/tmp`, a scratch dir → excluded), or a path that
|
|
2597
|
+
* could not be resolved on disk (→ excluded).
|
|
2598
|
+
*/
|
|
2599
|
+
type AdoptCandidateKind = "repo" | "non-repo" | "unresolved";
|
|
2600
|
+
type AdoptCandidate = {
|
|
2601
|
+
/** Source-root path as declared (relative to the manifest root). */
|
|
2602
|
+
path: string;
|
|
2603
|
+
/** On-disk classification; the filesystem probing that produces it is the caller's job. */
|
|
2604
|
+
kind: AdoptCandidateKind;
|
|
2558
2605
|
};
|
|
2559
|
-
type
|
|
2560
|
-
/**
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2606
|
+
type RosterAdoptionPlan = {
|
|
2607
|
+
/** Proposed `repos` entries: the candidates that are git repos (visibility left unset for the operator). */
|
|
2608
|
+
repos: RepoEntry[];
|
|
2609
|
+
/** Candidates excluded from the roster, with why (a non-repo directory, or an unresolvable path). */
|
|
2610
|
+
excluded: {
|
|
2611
|
+
path: string;
|
|
2612
|
+
kind: Exclude<AdoptCandidateKind, "repo">;
|
|
2613
|
+
}[];
|
|
2614
|
+
};
|
|
2615
|
+
/**
|
|
2616
|
+
* Plan a `repos` roster from classified source-root candidates (the actuator
|
|
2617
|
+
* behind `basou project adopt`). Pure: it partitions already-classified
|
|
2618
|
+
* candidates — the realpath / `.git` filesystem probing that produces each
|
|
2619
|
+
* `kind` is the caller's job, so this stays testable without disk I/O.
|
|
2620
|
+
*
|
|
2621
|
+
* A git repo becomes a roster entry (path only; visibility is left unset because
|
|
2622
|
+
* it is a human judgment, kept independent of the other axes). A non-repo
|
|
2623
|
+
* (commonly the generated workspace view) or an unresolvable path is excluded and
|
|
2624
|
+
* reported, so the operator sees what was dropped and why before editing. Repo
|
|
2625
|
+
* paths are deduped by normalized form, preserving the first declared form and
|
|
2626
|
+
* order.
|
|
2627
|
+
*/
|
|
2628
|
+
declare function planRosterAdoption(candidates: AdoptCandidate[]): RosterAdoptionPlan;
|
|
2629
|
+
|
|
2630
|
+
/**
|
|
2631
|
+
* The language of the GENERATED-VIEW chrome (headings, labels, verdict prose)
|
|
2632
|
+
* in handoff.md / orientation.md / decisions.md / report output.
|
|
2633
|
+
*
|
|
2634
|
+
* This is deliberately narrower than the manifest's repo `language` axis
|
|
2635
|
+
* (`en | ja | en+ja`): a generated view has exactly one chrome language, so
|
|
2636
|
+
* `en+ja` resolves to `en`. User data (decision titles, notes, labels, file
|
|
2637
|
+
* paths) always passes through verbatim — only the tool-generated strings are
|
|
2638
|
+
* localized, which is exactly the split this type exists to keep honest.
|
|
2639
|
+
*/
|
|
2640
|
+
type ViewLanguage = "en" | "ja";
|
|
2641
|
+
/**
|
|
2642
|
+
* Resolve the generated-view language from a manifest: the workspace speaks
|
|
2643
|
+
* the language of its ANCHOR repo (the `repos[]` entry whose path is `.`).
|
|
2644
|
+
*
|
|
2645
|
+
* Rules (fixed by design):
|
|
2646
|
+
* - anchor declares `ja` -> `ja`
|
|
2647
|
+
* - anchor declares `en` / `en+ja` -> `en` (a bilingual surface renders one
|
|
2648
|
+
* chrome; en is the shared floor)
|
|
2649
|
+
* - no roster / no anchor entry / no declared language -> `en` (the default
|
|
2650
|
+
* for basou's English-first OSS surface)
|
|
2651
|
+
*
|
|
2652
|
+
* Binding the view to the anchor's language is a deliberate, documented
|
|
2653
|
+
* coupling: the anchor is the planning/trail home the views live in, so its
|
|
2654
|
+
* declared audience is the views' audience. Other repos' languages do not
|
|
2655
|
+
* participate.
|
|
2656
|
+
*/
|
|
2657
|
+
declare function resolveViewLanguage(manifest: Pick<Manifest, "repos"> | null): ViewLanguage;
|
|
2658
|
+
/**
|
|
2659
|
+
* Manifest-reading convenience for the renderers: resolve the view language
|
|
2660
|
+
* for a workspace, defaulting to `en` when the manifest is missing or
|
|
2661
|
+
* unreadable (mirrors the orientation renderer's tolerant source_roots read —
|
|
2662
|
+
* a broken manifest must never break a view render).
|
|
2663
|
+
*/
|
|
2664
|
+
declare function resolveViewLanguageFromPaths(paths: BasouPaths): Promise<ViewLanguage>;
|
|
2665
|
+
/**
|
|
2666
|
+
* Every localized string the four view renderers emit, grouped per renderer
|
|
2667
|
+
* with a small `common` set for lines that are byte-identical across views.
|
|
2668
|
+
* Parameterized lines are functions so the two languages can order their
|
|
2669
|
+
* parts naturally.
|
|
2670
|
+
*
|
|
2671
|
+
* This module is the SINGLE home for generated Japanese — the view chrome here
|
|
2672
|
+
* and the instruction-file content in {@link PresetStrings} (the E-5
|
|
2673
|
+
* language-lint allowlist points here, not at the renderers/generators), so
|
|
2674
|
+
* "user data language" and "tool-generated content language" can never blur
|
|
2675
|
+
* together again.
|
|
2676
|
+
*/
|
|
2677
|
+
type ViewStrings = {
|
|
2678
|
+
/** Localized relative age for prose lines, e.g. "3日4時間前" / "3d 4h ago". */
|
|
2679
|
+
relativeAge: (startedAt: string | null, now: Date) => string;
|
|
2680
|
+
common: {
|
|
2681
|
+
/** "最終 session" — the latest live session pointer. */
|
|
2682
|
+
lastSessionLabel: string;
|
|
2683
|
+
/** "直近の判断" — the latest recorded decision pointer. */
|
|
2684
|
+
latestDecisionLabel: string;
|
|
2685
|
+
/** "直近の変更ファイル" — the latest session's related files. */
|
|
2686
|
+
recentFilesLabel: string;
|
|
2687
|
+
/** "理由" — a track's rationale label. */
|
|
2688
|
+
trackWhyLabel: string;
|
|
2689
|
+
/** Note that the latest decision comes from a different session. */
|
|
2690
|
+
decisionOtherSessionNote: (shortSessionId: string) => string;
|
|
2691
|
+
};
|
|
2692
|
+
orientation: {
|
|
2693
|
+
headingWhere: string;
|
|
2694
|
+
headingRecent: (sessionCount: number) => string;
|
|
2695
|
+
headingInFlight: string;
|
|
2696
|
+
headingForward: string;
|
|
2697
|
+
headingCurrency: string;
|
|
2698
|
+
inFlightTasksHeading: (n: number) => string;
|
|
2699
|
+
/**
|
|
2700
|
+
* Body line under the in-flight-tasks heading when NO task was ever
|
|
2701
|
+
* recorded here. "(none)" states that nothing is pending — a claim about
|
|
2702
|
+
* the work. This one claims only what it can see: that the record is
|
|
2703
|
+
* empty. It says nothing about whether the workspace should use tasks,
|
|
2704
|
+
* and names no command: the renderers report position, and a nudge that
|
|
2705
|
+
* cannot be silenced is noise (see `trackNudge`, which is gated).
|
|
2706
|
+
*/
|
|
2707
|
+
noTasksRecorded: string;
|
|
2708
|
+
/**
|
|
2709
|
+
* Body line under the in-flight-tasks heading when tasks ARE on record
|
|
2710
|
+
* here and every one of them parsed, with none open. A bare "(none)" is
|
|
2711
|
+
* literally true and still misread: it answers "is anything in flight?"
|
|
2712
|
+
* with a word that sounds like "nothing is happening". Work can be under
|
|
2713
|
+
* way and simply not filed as a task. This line leads with what the
|
|
2714
|
+
* record does hold, so it cannot be skimmed as its sibling below, and it
|
|
2715
|
+
* claims nothing about the work.
|
|
2716
|
+
*/
|
|
2717
|
+
noTasksInFlight: string;
|
|
2718
|
+
/**
|
|
2719
|
+
* Same heading, but a task file could not be read on THIS pass, so its
|
|
2720
|
+
* status is unknown and "none in flight" would be an assertion the
|
|
2721
|
+
* renderer cannot support. Says what it can see and stops.
|
|
2722
|
+
*
|
|
2723
|
+
* A standing condition, not a one-pass report: it holds every render until
|
|
2724
|
+
* the file is repaired or removed. It used to give way to its sibling on
|
|
2725
|
+
* the second render, because rebuilding the task index dropped the file it
|
|
2726
|
+
* could not parse and nothing enumerated it again.
|
|
2727
|
+
*/
|
|
2728
|
+
tasksUnreadable: string;
|
|
2729
|
+
/**
|
|
2730
|
+
* Appended under a NON-empty in-flight list when some task file could not
|
|
2731
|
+
* be read.
|
|
2732
|
+
*
|
|
2733
|
+
* The list above it is true and incomplete at the same time, and a reader
|
|
2734
|
+
* has no way to tell from a heading count that anything is missing. The
|
|
2735
|
+
* zero case already says so; saying nothing here would make "unreadable" a
|
|
2736
|
+
* fact basou reports only when it happens to have nothing else to report.
|
|
2737
|
+
*/
|
|
2738
|
+
tasksUnreadableAlongside: (n: number) => string;
|
|
2739
|
+
pendingApprovalsHeading: (n: number) => string;
|
|
2740
|
+
suspectSessionsHeading: (n: number) => string;
|
|
2741
|
+
openTracksHeading: (n: number) => string;
|
|
2742
|
+
/** Stale-decision honesty note under 直近の判断. */
|
|
2743
|
+
decisionStaleNote: (activityAge: string) => string;
|
|
2744
|
+
outOfRootWarning: (count: number, files: string) => string;
|
|
2745
|
+
recentEmpty: string;
|
|
2746
|
+
recentDecisionsLabel: string;
|
|
2747
|
+
recentNextStepLabel: string;
|
|
2748
|
+
recentChangedLabel: string;
|
|
2749
|
+
/** Trails the recent-files line when scratch paths were left out of it. */
|
|
2750
|
+
scratchOmitted: (count: number) => string;
|
|
2751
|
+
trackCloseInstruction: string;
|
|
2752
|
+
/** Forward-section pointer to `basou decision gaps`; omitted when the count is 0. */
|
|
2753
|
+
decisionGapsLine: (n: number) => string;
|
|
2754
|
+
nextStepRecordedLabel: (age: string) => string;
|
|
2755
|
+
noteStaleNote: (activityAge: string) => string;
|
|
2756
|
+
fallbackStaleDirection: string;
|
|
2757
|
+
fallbackStaleReferenceLabel: string;
|
|
2758
|
+
trackNudge: string;
|
|
2759
|
+
federatedFreshnessNote: string;
|
|
2760
|
+
bannerUnverifiable: (n: number) => string;
|
|
2761
|
+
bannerStale: (parts: string) => string;
|
|
2762
|
+
partNew: (n: number) => string;
|
|
2763
|
+
partUpdated: (n: number) => string;
|
|
2764
|
+
partsJoiner: string;
|
|
2765
|
+
verdictUnverifiable: (n: number) => [string, string];
|
|
2766
|
+
verdictStale: (parts: string) => [string, string];
|
|
2767
|
+
verdictUpdatedOnly: (n: number) => [string, string];
|
|
2768
|
+
verdictSuspectsAlso: (n: number) => string;
|
|
2769
|
+
verdictEmpty: [string, string];
|
|
2770
|
+
verdictUnprobed: (rel: string, tool: string) => [string, string];
|
|
2771
|
+
verdictCurrent: (rel: string, tool: string, hasHosts: boolean) => string;
|
|
2772
|
+
verdictSuspectsCaveat: (n: number) => string;
|
|
2773
|
+
verdictScopeDisclaimer: string;
|
|
2774
|
+
toolTerminal: string;
|
|
2775
|
+
toolHuman: string;
|
|
2776
|
+
toolImport: string;
|
|
2777
|
+
toolUnknown: string;
|
|
2778
|
+
};
|
|
2779
|
+
handoff: {
|
|
2780
|
+
headingCurrentState: string;
|
|
2781
|
+
headingRecentFiles: string;
|
|
2782
|
+
headingLatestDecision: string;
|
|
2783
|
+
headingOpenTracks: string;
|
|
2784
|
+
headingUnresolved: string;
|
|
2785
|
+
headingReadNext: string;
|
|
2786
|
+
headingNextWork: string;
|
|
2787
|
+
headingSessions: string;
|
|
2788
|
+
lastTaskLabel: string;
|
|
2789
|
+
/** "Work to do next" placeholder: tasks exist, none are open. */
|
|
2790
|
+
noPendingTasks: string;
|
|
2791
|
+
/** "Work to do next" placeholder: no task was ever recorded. */
|
|
2792
|
+
noTasksRecorded: string;
|
|
2793
|
+
decisionStaleNote: string;
|
|
2794
|
+
trackCloseInstruction: string;
|
|
2795
|
+
};
|
|
2796
|
+
decisions: {
|
|
2797
|
+
dateLabel: string;
|
|
2798
|
+
trackKindLine: string;
|
|
2799
|
+
decisionLabel: string;
|
|
2800
|
+
};
|
|
2801
|
+
report: {
|
|
2802
|
+
headingSummary: string;
|
|
2803
|
+
headingVolume: string;
|
|
2804
|
+
headingDecisions: string;
|
|
2805
|
+
headingApprovals: string;
|
|
2806
|
+
headingTasks: string;
|
|
2807
|
+
headingChangedFiles: string;
|
|
2808
|
+
headingSessions: string;
|
|
2809
|
+
headingIntegrity: string;
|
|
2810
|
+
};
|
|
2569
2811
|
};
|
|
2812
|
+
/** Look up the string table for a resolved view language. */
|
|
2813
|
+
declare function viewStrings(language: ViewLanguage): ViewStrings;
|
|
2570
2814
|
/**
|
|
2571
|
-
*
|
|
2572
|
-
*
|
|
2573
|
-
*
|
|
2574
|
-
*
|
|
2575
|
-
* -
|
|
2576
|
-
*
|
|
2577
|
-
*
|
|
2578
|
-
* Sort order is `Array.prototype.sort()` default (Unicode code-point
|
|
2579
|
-
* compare). ULIDs are Crockford base32 in uppercase, so the natural sort
|
|
2580
|
-
* is also chronological session-start order.
|
|
2581
|
-
*/
|
|
2582
|
-
declare function enumerateSessionDirs(paths: BasouPaths): Promise<string[]>;
|
|
2583
|
-
/**
|
|
2584
|
-
* Read and validate `<paths.sessions>/<sessionId>/session.yaml`.
|
|
2585
|
-
*
|
|
2586
|
-
* - Re-throws the yaml-store fixed-message `"YAML file not found"` for
|
|
2587
|
-
* ENOENT so the caller can branch on it.
|
|
2588
|
-
* - Throws `Error("Failed to read session.yaml", { cause })` for parse
|
|
2589
|
-
* failures and schema violations (cause is either the YAML parser error
|
|
2590
|
-
* or the zod error).
|
|
2591
|
-
*/
|
|
2592
|
-
declare function readSessionYaml(paths: BasouPaths, sessionId: string): Promise<Session>;
|
|
2593
|
-
/**
|
|
2594
|
-
* Apply a terminal-status mutation to a live session's `session.yaml` AND, in
|
|
2595
|
-
* the same locked write, stamp the tamper-evidence head anchor derived from the
|
|
2596
|
-
* on-disk `events.jsonl` tail. Used by the `exec` / `run` orchestrators for
|
|
2597
|
-
* BOTH terminal writers (the normal end-of-run finalize and the spawn-failure
|
|
2598
|
-
* `failed` finalize).
|
|
2599
|
-
*
|
|
2600
|
-
* Why locked + anchor-from-tail: live appends chain the LOG only and leave the
|
|
2601
|
-
* anchor for finalize. Reading the final tail under the session lock means a
|
|
2602
|
-
* foreign line appended just before finalize (e.g. a `decision record` attached
|
|
2603
|
-
* to a still-running session) is included in the anchor, and a foreign attach
|
|
2604
|
-
* that arrives after the terminal status is set is rejected by the attach gate
|
|
2605
|
-
* — so the anchor can never disagree with the at-rest log. The whole-document
|
|
2606
|
-
* read-modify-write also preserves any field a foreign locked writer set (e.g.
|
|
2607
|
-
* a task attach's `task_id`).
|
|
2608
|
-
*
|
|
2609
|
-
* The anchor is written only when the log is actually chained with at least one
|
|
2610
|
-
* line; a legacy unchained session (and an empty log) is left with no
|
|
2611
|
-
* `integrity` anchor, matching the import writers. The mutator receives the
|
|
2612
|
-
* full {@link Session} document and typically sets
|
|
2613
|
-
* `session.session.status` / `ended_at` / `invocation.exit_code` /
|
|
2614
|
-
* `related_files`.
|
|
2615
|
-
*
|
|
2616
|
-
* Throws the {@link inspectChainTail} errors (torn / mixed log), the
|
|
2617
|
-
* {@link readSessionYaml} errors, a zod error if the mutation produces an
|
|
2618
|
-
* invalid document, or `Error("Failed to overwrite YAML file")` on a disk
|
|
2619
|
-
* failure.
|
|
2815
|
+
* Resolve a GENERATED INSTRUCTION-FILE's content language from the target
|
|
2816
|
+
* repo's declared `language`. Unlike the views (workspace-level artifacts that
|
|
2817
|
+
* follow the anchor), a preset block lives inside one repo's instruction file,
|
|
2818
|
+
* so its audience is that repo's declared audience: `ja` renders Japanese
|
|
2819
|
+
* (byte-identical to the pre-i18n output), `en` / `en+ja` / undeclared render
|
|
2820
|
+
* English (one content language per generated block; en is the shared floor).
|
|
2620
2821
|
*/
|
|
2621
|
-
declare function
|
|
2822
|
+
declare function resolveRepoContentLanguage(language: RepoLanguage | undefined): ViewLanguage;
|
|
2622
2823
|
/**
|
|
2623
|
-
*
|
|
2624
|
-
*
|
|
2625
|
-
*
|
|
2626
|
-
*
|
|
2627
|
-
*
|
|
2628
|
-
*
|
|
2629
|
-
* - Rule B (`running_no_end_event`): no `session_ended` event and the last
|
|
2630
|
-
* event is older than {@link STUCK_THRESHOLD_MS}. The process likely
|
|
2631
|
-
* crashed or was killed.
|
|
2632
|
-
*
|
|
2633
|
-
* Sessions that are not `running` are never suspect.
|
|
2824
|
+
* Resolve the content language of a WORKSPACE-LEVEL instruction artifact (the
|
|
2825
|
+
* view's AGENTS.md block, the anchor's starter) from an already-gathered
|
|
2826
|
+
* roster: the entry flagged `anchor` speaks for the workspace, mirroring the
|
|
2827
|
+
* views' anchor-language rule. No anchor entry (or no declared language)
|
|
2828
|
+
* resolves to English. When more than one entry carries the flag, the first
|
|
2829
|
+
* wins (declared order).
|
|
2634
2830
|
*
|
|
2635
|
-
*
|
|
2636
|
-
*
|
|
2637
|
-
*
|
|
2831
|
+
* Note the anchor is identified by the CALLER-SET flag, not by this module:
|
|
2832
|
+
* {@link resolveViewLanguage} keys on the manifest path being `.`, while the
|
|
2833
|
+
* instruction-file callers flag the anchor by resolved-path identity. For a
|
|
2834
|
+
* conventional manifest (anchor declared as `.`) the two agree; a roster that
|
|
2835
|
+
* reaches the anchor only through an aliased path is where they can diverge,
|
|
2836
|
+
* and the caller's flag is authoritative for the instruction files.
|
|
2638
2837
|
*/
|
|
2639
|
-
declare function
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
}
|
|
2643
|
-
declare function loadSessionEntries(paths: BasouPaths, options: LoadSessionEntriesOptions): Promise<SessionEntry[]>;
|
|
2838
|
+
declare function resolveAnchorContentLanguage(repos: ReadonlyArray<{
|
|
2839
|
+
anchor?: boolean | undefined;
|
|
2840
|
+
language?: RepoLanguage | undefined;
|
|
2841
|
+
}>): ViewLanguage;
|
|
2644
2842
|
/**
|
|
2645
|
-
*
|
|
2646
|
-
*
|
|
2647
|
-
*
|
|
2648
|
-
*
|
|
2649
|
-
*
|
|
2650
|
-
*
|
|
2651
|
-
* cannot be enumerated is reported via `onRootUnavailable` and skipped; the
|
|
2652
|
-
* local root's errors propagate, matching {@link loadSessionEntries}.
|
|
2843
|
+
* Every localized string the instruction-file generators emit: the per-repo
|
|
2844
|
+
* preset block, the workspace view's block, and the anchor's starter. Lives in
|
|
2845
|
+
* this module for the same reason as {@link ViewStrings}: it is the SINGLE
|
|
2846
|
+
* home for generated Japanese, so the language-lint E-5 allowlist stays one
|
|
2847
|
+
* file and "generated content language" is always a declaration-driven table
|
|
2848
|
+
* lookup, never a hardcode.
|
|
2653
2849
|
*/
|
|
2654
|
-
|
|
2850
|
+
type PresetStrings = {
|
|
2851
|
+
repoBlock: {
|
|
2852
|
+
heading: string;
|
|
2853
|
+
intro: string;
|
|
2854
|
+
/** Source git-visibility, rendered with the consequence the agent must respect. */
|
|
2855
|
+
visibilityLabel: (v: RepoVisibility | undefined) => string;
|
|
2856
|
+
/**
|
|
2857
|
+
* Source language (commits/comments/code), rendered with the audience it
|
|
2858
|
+
* serves. Invariant note: the table itself is SELECTED by this same field
|
|
2859
|
+
* (ja -> JA table, everything else -> EN), so the JA table's en / en+ja /
|
|
2860
|
+
* unset branches and the EN table's ja branch are unreachable from
|
|
2861
|
+
* renderPresetBlock — they exist for table completeness (and the
|
|
2862
|
+
* both-language sweep test), not because a render can emit them.
|
|
2863
|
+
*/
|
|
2864
|
+
sourceLanguageLabel: (l: RepoLanguage | undefined) => string;
|
|
2865
|
+
/** Published-surface kind. */
|
|
2866
|
+
publishKindLabel: (k: PublishTarget["kind"]) => string;
|
|
2867
|
+
/** A published surface's visibility (independent of the source repo's). */
|
|
2868
|
+
publishVisibilityLabel: (v: RepoVisibility | undefined) => string;
|
|
2869
|
+
/** A published surface's content language (read by end users; may differ from source). */
|
|
2870
|
+
contentLanguageLabel: (l: RepoLanguage | undefined) => string;
|
|
2871
|
+
/** "ソース可視性" — the source-visibility line label. */
|
|
2872
|
+
sourceVisibilityLabel: string;
|
|
2873
|
+
/** "ソース言語" — the source-language line label. */
|
|
2874
|
+
sourceLanguageLineLabel: string;
|
|
2875
|
+
/** "- 配信物: なし" — no published surfaces. */
|
|
2876
|
+
publishesNone: string;
|
|
2877
|
+
/** "- 配信物:" — the published-surfaces list header. */
|
|
2878
|
+
publishesHeader: string;
|
|
2879
|
+
};
|
|
2880
|
+
viewBlock: {
|
|
2881
|
+
heading: string;
|
|
2882
|
+
intro: string;
|
|
2883
|
+
selfNote: (viewName: string) => string;
|
|
2884
|
+
aggregates: (repoCount: number) => string;
|
|
2885
|
+
reposHeading: string;
|
|
2886
|
+
tableHeader: string;
|
|
2887
|
+
/** Instruction-file ownership labels: who writes the repo's AGENTS.md. */
|
|
2888
|
+
instructionsAnchor: string;
|
|
2889
|
+
instructionsSelf: string;
|
|
2890
|
+
instructionsHub: string;
|
|
2891
|
+
/** "未設定" — the short table cell for an undeclared visibility / language. */
|
|
2892
|
+
unsetShort: string;
|
|
2893
|
+
commitHeading: string;
|
|
2894
|
+
commitBody: string;
|
|
2895
|
+
conventionsHeading: string;
|
|
2896
|
+
conventionsBody: string;
|
|
2897
|
+
/** Heading for {@link handoffPointer}. Its own, so the pointer is not filed
|
|
2898
|
+
* under "Required reading" while telling the reader not to read it through. */
|
|
2899
|
+
handoffHeading: string;
|
|
2900
|
+
/**
|
|
2901
|
+
* Where the session roster lives. One line, because the adjudication that
|
|
2902
|
+
* chose this destination capped session-start injection: the roster itself
|
|
2903
|
+
* must never be injected, only its address.
|
|
2904
|
+
*/
|
|
2905
|
+
handoffPointer: string;
|
|
2906
|
+
principlesHeading: string;
|
|
2907
|
+
principleStateless: string;
|
|
2908
|
+
principleNoFiles: string;
|
|
2909
|
+
};
|
|
2910
|
+
anchorStarter: {
|
|
2911
|
+
identityLine: (title: string) => string;
|
|
2912
|
+
starterNote: string;
|
|
2913
|
+
basicsHeading: string;
|
|
2914
|
+
basicsTodo: string;
|
|
2915
|
+
commitHeading: string;
|
|
2916
|
+
commitPlanning: string;
|
|
2917
|
+
commitImplementation: string;
|
|
2918
|
+
commitView: string;
|
|
2919
|
+
conventionsHeading: string;
|
|
2920
|
+
conventionsBody: string;
|
|
2921
|
+
viewPointerLine: (viewName: string) => string;
|
|
2922
|
+
/** Same route as the view block's, for the anchor — which is where `.basou/` lives. */
|
|
2923
|
+
handoffHeading: string;
|
|
2924
|
+
handoffPointer: string;
|
|
2925
|
+
policyHeading: string;
|
|
2926
|
+
policyTodo: string[];
|
|
2927
|
+
};
|
|
2928
|
+
};
|
|
2929
|
+
/** Look up the instruction-file string table for a resolved content language. */
|
|
2930
|
+
declare function presetStrings(language: ViewLanguage): PresetStrings;
|
|
2655
2931
|
|
|
2656
2932
|
type DecisionsRendererInput = {
|
|
2657
2933
|
paths: BasouPaths;
|
|
@@ -3198,6 +3474,19 @@ declare function prefixedUlid<P extends IdPrefix>(prefix: P): PrefixedId<P>;
|
|
|
3198
3474
|
*/
|
|
3199
3475
|
declare function isValidPrefixedId(value: string): boolean;
|
|
3200
3476
|
|
|
3477
|
+
/**
|
|
3478
|
+
* `schema_version` stamped on NEWLY WRITTEN `.basou/tasks/<id>.md` front matter.
|
|
3479
|
+
*
|
|
3480
|
+
* 0.2.0 requires seconds in every timestamp. That NARROWS the field's domain,
|
|
3481
|
+
* which §7.3 forbids except under the vacuous-narrowing rule the same section
|
|
3482
|
+
* states: no value basou has ever written omits seconds, so the set of
|
|
3483
|
+
* documents this refuses is empty. See `docs/spec/schemas.md` for the read
|
|
3484
|
+
* rule and the measurement. The narrowing is shared with the event format, so
|
|
3485
|
+
* every durable document bumps together.
|
|
3486
|
+
*
|
|
3487
|
+
* Note: basou writes this document.
|
|
3488
|
+
*/
|
|
3489
|
+
declare const TASK_SCHEMA_VERSION: "0.2.0";
|
|
3201
3490
|
/**
|
|
3202
3491
|
* Task lifecycle states.
|
|
3203
3492
|
*
|
|
@@ -3214,8 +3503,8 @@ declare function isValidPrefixedId(value: string): boolean;
|
|
|
3214
3503
|
* Self-edges are rejected so the audit trail stays monotonic.
|
|
3215
3504
|
*/
|
|
3216
3505
|
declare const TaskStatusSchema: z.ZodEnum<{
|
|
3217
|
-
in_progress: "in_progress";
|
|
3218
3506
|
planned: "planned";
|
|
3507
|
+
in_progress: "in_progress";
|
|
3219
3508
|
done: "done";
|
|
3220
3509
|
cancelled: "cancelled";
|
|
3221
3510
|
}>;
|
|
@@ -3235,8 +3524,8 @@ declare const TaskSchema: z.ZodObject<{
|
|
|
3235
3524
|
title: z.ZodString;
|
|
3236
3525
|
label: z.ZodOptional<z.ZodString>;
|
|
3237
3526
|
status: z.ZodEnum<{
|
|
3238
|
-
in_progress: "in_progress";
|
|
3239
3527
|
planned: "planned";
|
|
3528
|
+
in_progress: "in_progress";
|
|
3240
3529
|
done: "done";
|
|
3241
3530
|
cancelled: "cancelled";
|
|
3242
3531
|
}>;
|
|
@@ -3425,9 +3714,15 @@ declare function writeTaskFile(paths: BasouPaths, taskId: string, doc: TaskDocum
|
|
|
3425
3714
|
* the caller's `options.onSkip` hook in {@link loadTaskEntries} so list
|
|
3426
3715
|
* commands can show a warning row.
|
|
3427
3716
|
*
|
|
3428
|
-
*
|
|
3717
|
+
* Ids come back in ULID-ascending order: the disk scan sorts by filename,
|
|
3718
|
+
* which matches ULID order, and {@link rebuildTaskIndex} sorts what it writes,
|
|
3719
|
+
* so an index basou wrote is already in that order. An index edited by hand
|
|
3720
|
+
* into some other order is returned in it — no caller depends on the order,
|
|
3721
|
+
* and re-sorting a trusted cache would hide that it was used.
|
|
3722
|
+
*
|
|
3429
3723
|
* Empty directory or ENOENT → `[]`. Other I/O failures throw
|
|
3430
|
-
* `"Failed to enumerate tasks"
|
|
3724
|
+
* `"Failed to enumerate tasks"`, unless a valid index is available to answer
|
|
3725
|
+
* from instead.
|
|
3431
3726
|
*/
|
|
3432
3727
|
declare function enumerateTaskIds(paths: BasouPaths): Promise<string[]>;
|
|
3433
3728
|
/**
|
|
@@ -3638,7 +3933,8 @@ type ReconcileFailure = {
|
|
|
3638
3933
|
phase: TaskWriteAfterEventPhase | null;
|
|
3639
3934
|
};
|
|
3640
3935
|
/**
|
|
3641
|
-
* Batch audit result. Order follows `enumerateTaskIds(paths)
|
|
3936
|
+
* Batch audit result. Order follows `enumerateTaskIds(paths)`, which is
|
|
3937
|
+
* ULID-ascending for any index basou wrote and for every disk scan.
|
|
3642
3938
|
* `scanned` is the number of readable task.md files processed (= excludes
|
|
3643
3939
|
* malformed task.md from the count so an integrity-broken file does not
|
|
3644
3940
|
* pad the total).
|
|
@@ -3973,6 +4269,35 @@ type HandoffRendererResult = {
|
|
|
3973
4269
|
*/
|
|
3974
4270
|
declare function renderHandoff(input: HandoffRendererInput): Promise<HandoffRendererResult>;
|
|
3975
4271
|
|
|
4272
|
+
/** What a build knows about itself. `commit` is `"unknown"` outside a checkout. */
|
|
4273
|
+
type BuildStamp = {
|
|
4274
|
+
readonly version: string;
|
|
4275
|
+
readonly commit: string;
|
|
4276
|
+
readonly committedAt: string;
|
|
4277
|
+
};
|
|
4278
|
+
/**
|
|
4279
|
+
* Parse an injected stamp. Separate from the constant below so it is reachable
|
|
4280
|
+
* from a test: under vitest the module loads from SOURCE, where the injected
|
|
4281
|
+
* identifier does not exist, so every line of the parse would otherwise be
|
|
4282
|
+
* unreachable -- a guarantee with no test behind it, which is the shape of
|
|
4283
|
+
* omission this whole feature exists to correct.
|
|
4284
|
+
*
|
|
4285
|
+
* Anything unparseable yields `undefined` rather than throwing: a malformed
|
|
4286
|
+
* stamp must not stop the CLI from starting.
|
|
4287
|
+
*/
|
|
4288
|
+
declare function parseBuildStamp(raw: string | undefined): BuildStamp | undefined;
|
|
4289
|
+
/**
|
|
4290
|
+
* Core's own build identity.
|
|
4291
|
+
*
|
|
4292
|
+
* Core is stamped separately from the CLI because the CLI does not bundle it:
|
|
4293
|
+
* `cli/dist` and `core/dist` are distinct artifacts that a partial build can
|
|
4294
|
+
* leave at different commits. A fresh CLI in front of a stale core is the
|
|
4295
|
+
* dangerous half of that pair -- core is where the renderers and importers
|
|
4296
|
+
* live, so the behaviour would be the old one while the CLI reported the new
|
|
4297
|
+
* version.
|
|
4298
|
+
*/
|
|
4299
|
+
declare const BASOU_CORE_BUILD: BuildStamp | undefined;
|
|
4300
|
+
|
|
3976
4301
|
/**
|
|
3977
4302
|
* Parse a unit-suffixed duration string (e.g. `30s`, `5m`, `1h`, `100ms`)
|
|
3978
4303
|
* into milliseconds.
|
|
@@ -4355,6 +4680,13 @@ type OrientationSummary = {
|
|
|
4355
4680
|
* does not sink into the flat decision list. Empty when none are open.
|
|
4356
4681
|
*/
|
|
4357
4682
|
openTracks: TrackRecord[];
|
|
4683
|
+
/**
|
|
4684
|
+
* Decisions recorded by `basou decision capture` that are still open and that
|
|
4685
|
+
* no task carries — the count `basou decision gaps` lists. Surfaced here as a
|
|
4686
|
+
* single number because a ratified plan that became no task is invisible
|
|
4687
|
+
* otherwise, and a command nobody is told to run does not fix that.
|
|
4688
|
+
*/
|
|
4689
|
+
openDecisionGaps: number;
|
|
4358
4690
|
/**
|
|
4359
4691
|
* Most recent `note_added` over non-archived sessions — the recorded next
|
|
4360
4692
|
* step / handoff ("next step") surfaced in the forward section; null when none.
|
|
@@ -4391,6 +4723,14 @@ type OrientationSummary = {
|
|
|
4391
4723
|
* zero in-flight count distinguish "all closed" from "never used here".
|
|
4392
4724
|
* See {@link anyTaskEverRecorded}: a live count is NOT this. */
|
|
4393
4725
|
anyTaskEverRecorded: boolean;
|
|
4726
|
+
/** How many task files this render could not read.
|
|
4727
|
+
*
|
|
4728
|
+
* A standing count: the task index is reconciled against the tasks directory
|
|
4729
|
+
* on every enumeration, so a file that cannot be parsed keeps being attempted
|
|
4730
|
+
* — and keeps being counted — until it is repaired or removed. It used to
|
|
4731
|
+
* read zero from the second render on, because rebuilding the index dropped
|
|
4732
|
+
* the file and nothing enumerated it again. */
|
|
4733
|
+
unreadableTaskCount: number;
|
|
4394
4734
|
/** Tasks whose status is `planned` ("where am I heading"). */
|
|
4395
4735
|
plannedTasks: PlannedTask[];
|
|
4396
4736
|
pendingApprovals: PendingApproval[];
|
|
@@ -4736,8 +5076,9 @@ type ViewPresetInput = {
|
|
|
4736
5076
|
* operator-specific string is embedded), so re-running on an unchanged manifest
|
|
4737
5077
|
* produces byte-identical output. The view is a workspace-level artifact, so
|
|
4738
5078
|
* its content language follows the ANCHOR entry's declared language (mirroring
|
|
4739
|
-
* the generated views' rule)
|
|
4740
|
-
*
|
|
5079
|
+
* the generated views' rule). It no longer reproduces the pre-i18n output: the
|
|
5080
|
+
* block gained a line naming where the session roster lives, which that output
|
|
5081
|
+
* predates. The repos are listed in the order supplied. An empty roster
|
|
4741
5082
|
* still renders cleanly (a header-only table, empty lists). Returns the block
|
|
4742
5083
|
* WITHOUT a trailing newline; the marker writer adds the surrounding structure.
|
|
4743
5084
|
*/
|
|
@@ -5645,6 +5986,120 @@ type WorkspaceViewPlan = {
|
|
|
5645
5986
|
*/
|
|
5646
5987
|
declare function planWorkspaceView(facts: ViewRepoFact[], existing?: ExistingViewLink[], rosterNames?: string[]): WorkspaceViewPlan;
|
|
5647
5988
|
|
|
5989
|
+
/** Prefix of the token embedded in a delivery; the content digest follows it. */
|
|
5990
|
+
declare const PROTOCOL_UPDATE_TOKEN_PREFIX = "basou:protocol-updated";
|
|
5991
|
+
/** What the block records about itself. */
|
|
5992
|
+
type ProtocolStamp = {
|
|
5993
|
+
/** When the block's rendered protocol text last CHANGED (ISO 8601, UTC). */
|
|
5994
|
+
changedAt: string;
|
|
5995
|
+
/** Truncated digest of that rendered text. */
|
|
5996
|
+
contentHash: string;
|
|
5997
|
+
};
|
|
5998
|
+
/** Truncated digest of the block's rendered protocol text. */
|
|
5999
|
+
declare function protocolBlockHash(sections: string): string;
|
|
6000
|
+
/**
|
|
6001
|
+
* The delivery's dedupe token for a given block state.
|
|
6002
|
+
*
|
|
6003
|
+
* It carries the content digest rather than being a bare literal, so "already
|
|
6004
|
+
* delivered" means "already delivered THIS text". A second update inside one
|
|
6005
|
+
* session — usually the correction of the first, after watching an agent
|
|
6006
|
+
* misapply it — is a different digest and still lands. A bare literal would
|
|
6007
|
+
* make the one edit most worth delivering the one guaranteed not to arrive.
|
|
6008
|
+
*/
|
|
6009
|
+
declare function protocolUpdateToken(contentHash: string): string;
|
|
6010
|
+
/**
|
|
6011
|
+
* Render the stamp line.
|
|
6012
|
+
*
|
|
6013
|
+
* Nothing operator-authored goes on it — only a timestamp and a digest — so a
|
|
6014
|
+
* source path or a protocol body containing a space, a quote, or a `-->` cannot
|
|
6015
|
+
* break the line it is rendered into.
|
|
6016
|
+
*/
|
|
6017
|
+
declare function renderProtocolStamp(stamp: ProtocolStamp): string;
|
|
6018
|
+
/**
|
|
6019
|
+
* Find and parse the stamp line in a rendered block body.
|
|
6020
|
+
*
|
|
6021
|
+
* Returns `null` when the block carries no readable stamp — a block rendered by
|
|
6022
|
+
* a basou older than this feature, a hand-deleted stamp, a mangled one. A null
|
|
6023
|
+
* means "cannot tell", and every caller treats it as "say nothing": the point
|
|
6024
|
+
* of the feature is to speak only when basou actually knows something changed.
|
|
6025
|
+
*/
|
|
6026
|
+
declare function parseProtocolStamp(blockBody: string): ProtocolStamp | null;
|
|
6027
|
+
/**
|
|
6028
|
+
* Build the stamp for the block about to be written: keep the previous
|
|
6029
|
+
* `changedAt` when the rendered text is unchanged, and set it to `now`
|
|
6030
|
+
* otherwise.
|
|
6031
|
+
*
|
|
6032
|
+
* `sections` is the rendered protocol text exactly as it will appear under the
|
|
6033
|
+
* stamp — the same bytes a session reads and the same bytes a delivery carries.
|
|
6034
|
+
* Hashing anything else (the raw source files, say) would let bytes no session
|
|
6035
|
+
* ever sees move the stamp, and basou would then tell a session that text it
|
|
6036
|
+
* already holds supersedes what it already holds.
|
|
6037
|
+
*
|
|
6038
|
+
* `changedAt` is forced strictly forward when the text did change. Wall-clock
|
|
6039
|
+
* time can move backwards — an NTP correction, a laptop waking in another
|
|
6040
|
+
* timezone — and a stamp dated before the session start would drop the delivery
|
|
6041
|
+
* for the rest of that session, silently and permanently.
|
|
6042
|
+
*/
|
|
6043
|
+
declare function carryForwardProtocolStamp(input: {
|
|
6044
|
+
sections: string;
|
|
6045
|
+
previous: ProtocolStamp | null;
|
|
6046
|
+
now: string;
|
|
6047
|
+
}): ProtocolStamp;
|
|
6048
|
+
/**
|
|
6049
|
+
* The rendered protocol text inside a block: everything below the stamp line.
|
|
6050
|
+
*
|
|
6051
|
+
* Anchored on the stamp rather than on "skip the leading comments" so a
|
|
6052
|
+
* protocol whose own body opens with an HTML comment keeps it. Returns `null`
|
|
6053
|
+
* when there is no stamp line to anchor on, and an empty string when the block
|
|
6054
|
+
* holds a stamp and nothing else.
|
|
6055
|
+
*
|
|
6056
|
+
* Takes a block BODY, but stops at a closing marker line if one is present, so
|
|
6057
|
+
* handing it a whole file yields the same answer instead of a digest that
|
|
6058
|
+
* silently includes the marker and matches nothing.
|
|
6059
|
+
*/
|
|
6060
|
+
declare function protocolSectionsFrom(blockBody: string): string | null;
|
|
6061
|
+
/**
|
|
6062
|
+
* The rendered protocol text inside a block written before stamps existed:
|
|
6063
|
+
* everything below the managed note.
|
|
6064
|
+
*
|
|
6065
|
+
* Only for reading the block an upgrade is about to replace. Knowing what that
|
|
6066
|
+
* block held is what lets an upgrade stay silent — if the text is the same, no
|
|
6067
|
+
* running session is owed anything, and dating the new stamp at `now` would
|
|
6068
|
+
* announce a change to every session on the machine the first time the new
|
|
6069
|
+
* basou syncs. Less precise than the stamped path (a protocol body opening
|
|
6070
|
+
* with its own HTML comment loses that line here), which is why it is confined
|
|
6071
|
+
* to blocks that carry no stamp: a wrong answer costs one redundant delivery,
|
|
6072
|
+
* never a wrong one.
|
|
6073
|
+
*/
|
|
6074
|
+
declare function unstampedProtocolSectionsFrom(blockBody: string): string;
|
|
6075
|
+
/**
|
|
6076
|
+
* Whether a session that started at `sessionStartedAt` is holding an older copy
|
|
6077
|
+
* of the block than the one the stamp describes.
|
|
6078
|
+
*
|
|
6079
|
+
* A change dated at or before the start is one the session already read. An
|
|
6080
|
+
* unparseable start yields `false` rather than "everything": without a session
|
|
6081
|
+
* start there is no "after".
|
|
6082
|
+
*/
|
|
6083
|
+
declare function isProtocolUpdateDue(input: {
|
|
6084
|
+
stamp: ProtocolStamp;
|
|
6085
|
+
sessionStartedAt: string;
|
|
6086
|
+
}): boolean;
|
|
6087
|
+
/**
|
|
6088
|
+
* The text handed to the running session: the protocols themselves, not a
|
|
6089
|
+
* pointer to them.
|
|
6090
|
+
*
|
|
6091
|
+
* basou cannot observe whether an agent re-read a file, so a notice saying "go
|
|
6092
|
+
* and re-read" would put the one step that decides the outcome outside what
|
|
6093
|
+
* basou can see. Carrying the text makes the delivery and the reading the same
|
|
6094
|
+
* act. It does not make the ADOPTION observable — nothing basou can do would —
|
|
6095
|
+
* but it removes the step that was avoidably invisible.
|
|
6096
|
+
*
|
|
6097
|
+
* The complete current set is sent, not a diff, so the lead line's claim is
|
|
6098
|
+
* exactly true: after this, the set below is the whole of the standing
|
|
6099
|
+
* protocols, and anything read at session start that is absent here is gone.
|
|
6100
|
+
*/
|
|
6101
|
+
declare function renderProtocolUpdate(sections: string, stamp: ProtocolStamp): string;
|
|
6102
|
+
|
|
5648
6103
|
/**
|
|
5649
6104
|
* `schema_version` of each on-disk format, keyed by artifact basename.
|
|
5650
6105
|
*
|
|
@@ -5662,14 +6117,14 @@ declare function planWorkspaceView(facts: ViewRepoFact[], existing?: ExistingVie
|
|
|
5662
6117
|
* changed without the envelope's own format changing.
|
|
5663
6118
|
*/
|
|
5664
6119
|
declare const JSON_SCHEMA_VERSIONS: {
|
|
5665
|
-
readonly manifest: "0.
|
|
5666
|
-
readonly session: "0.
|
|
5667
|
-
readonly event: "0.
|
|
5668
|
-
readonly task: "0.
|
|
5669
|
-
readonly approval: "0.
|
|
6120
|
+
readonly manifest: "0.2.0";
|
|
6121
|
+
readonly session: "0.2.0";
|
|
6122
|
+
readonly event: "0.3.0";
|
|
6123
|
+
readonly task: "0.2.0";
|
|
6124
|
+
readonly approval: "0.2.0";
|
|
5670
6125
|
readonly status: "0.1.0";
|
|
5671
6126
|
readonly "task-index": "0.1.0";
|
|
5672
|
-
readonly "session-import": "0.
|
|
6127
|
+
readonly "session-import": "0.2.0";
|
|
5673
6128
|
};
|
|
5674
6129
|
/** One emitted JSON Schema artifact. */
|
|
5675
6130
|
type JsonSchemaArtifact = {
|
|
@@ -5809,14 +6264,21 @@ declare const SchemaVersionSchema: z.ZodString;
|
|
|
5809
6264
|
* and would need the pattern written a second time, which is a second place to
|
|
5810
6265
|
* forget. {@link SchemaVersionSchema} takes the same form for the same reason.
|
|
5811
6266
|
*
|
|
5812
|
-
* It deliberately does NOT declare `format: "date-time"`.
|
|
5813
|
-
*
|
|
5814
|
-
*
|
|
5815
|
-
*
|
|
5816
|
-
*
|
|
5817
|
-
*
|
|
5818
|
-
*
|
|
5819
|
-
*
|
|
6267
|
+
* It deliberately does NOT declare `format: "date-time"`. The sets used to
|
|
6268
|
+
* CROSS — basou took a timestamp without seconds, which RFC 3339 does not —
|
|
6269
|
+
* and declaring the format made one artifact answer two ways from the same
|
|
6270
|
+
* bytes: a validator asserting it rejected `2026-09-16T01:23Z`, one treating
|
|
6271
|
+
* it as an annotation (the JSON Schema 2020-12 default) accepted it.
|
|
6272
|
+
*
|
|
6273
|
+
* Requiring seconds ended the crossing: this set is now a strict SUBSET of
|
|
6274
|
+
* RFC 3339 `date-time`, since uppercase-only and no-leap-second are
|
|
6275
|
+
* restrictions on it. So the format could be declared truthfully again. It is
|
|
6276
|
+
* still not declared, for a different reason than before — the `pattern` is
|
|
6277
|
+
* the whole contract and the format names a strictly larger set, so declaring
|
|
6278
|
+
* it would say less than the artifact already says while reintroducing a
|
|
6279
|
+
* keyword whose enforcement varies by validator. Reinstating it is a decision
|
|
6280
|
+
* about what the artifact should assert, not a correction; `description` is
|
|
6281
|
+
* what states this set, because no format name does.
|
|
5820
6282
|
*/
|
|
5821
6283
|
declare const IsoTimestampSchema: z.ZodString;
|
|
5822
6284
|
/** Workspace ID schema: validates `ws_<26-char ULID>`. */
|
|
@@ -5849,6 +6311,18 @@ type RiskLevel = z.infer<typeof RiskLevelSchema>;
|
|
|
5849
6311
|
* non-empty string in v0.1; a stricter enum may be introduced post-v0.1.
|
|
5850
6312
|
*/
|
|
5851
6313
|
declare const EventSourceSchema: z.ZodString;
|
|
6314
|
+
/**
|
|
6315
|
+
* The `source` basou stamps on an event it wrote itself, in response to a
|
|
6316
|
+
* `basou` command the operator (or an agent acting for them) ran — as opposed
|
|
6317
|
+
* to an event an importer derived from a vendor transcript.
|
|
6318
|
+
*
|
|
6319
|
+
* It is a named constant because a reader distinguishes the two: `plan-gaps`
|
|
6320
|
+
* admits a decision to its population only when this source recorded it, so a
|
|
6321
|
+
* writer drifting from this literal would silently shrink that population
|
|
6322
|
+
* rather than fail. Every local writer imports this rather than repeating the
|
|
6323
|
+
* string, so the reader's predicate and the writers have one origin.
|
|
6324
|
+
*/
|
|
6325
|
+
declare const LOCAL_CLI_EVENT_SOURCE = "local-cli";
|
|
5852
6326
|
|
|
5853
6327
|
/**
|
|
5854
6328
|
* Schema for `.basou/status.json` — a forward-incompat cache of the current
|
|
@@ -6993,7 +7467,7 @@ type ImportSessionResult = {
|
|
|
6993
7467
|
/**
|
|
6994
7468
|
* Import a round-trip JSON payload into `.basou/sessions/<new>/`. The caller
|
|
6995
7469
|
* MUST validate the payload against {@link SessionImportPayloadSchema} first
|
|
6996
|
-
* and gate the `schema_version ===
|
|
7470
|
+
* and gate the `schema_version === SESSION_IMPORT_SCHEMA_VERSION` check externally; this
|
|
6997
7471
|
* function trusts both invariants.
|
|
6998
7472
|
*
|
|
6999
7473
|
* On success a fresh session ID is minted and a complete
|
|
@@ -7181,4 +7655,4 @@ declare function overwriteYamlFile(filePath: string, value: unknown): Promise<vo
|
|
|
7181
7655
|
*/
|
|
7182
7656
|
declare const BASOU_CORE_VERSION = "0.1.0";
|
|
7183
7657
|
|
|
7184
|
-
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, EVENT_SCHEMA_VERSION, 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_VERSIONS, 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_IMPORT_SCHEMA_VERSION, 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, ZERO_DURATION_RETIRED_SINCE, 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, hasRetiredZeroDuration, 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, readObservedDuration, 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, writeObservedDuration, writeStatus, writeTaskFile, writeYamlFile };
|
|
7658
|
+
export { ACTIVE_GAP_CAP_MS, AGENT_INFRA_DIRS, APPROVAL_SCHEMA_VERSION, 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_BUILD, BASOU_CORE_VERSION, type BasouPaths, type BuildStamp, 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, DECISION_GAPS_EPOCH, DEFAULT_STOP_HOOK_MIN_EDITS, type DayWorkStats, type DecisionGap, type DecisionGapsExcluded, type DecisionGapsIncomplete, type DecisionGapsInput, type DecisionGapsScope, type DecisionGapsSummary, DecisionIdSchema, type DecisionRecordedEvent, type DecisionsRendererInput, type DecisionsRendererResult, type DeleteTaskInput, type DeleteTaskResult, type DiffResult, EVENT_SCHEMA_VERSION, 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_VERSIONS, type JsonSchemaArtifact, LOCAL_CLI_EVENT_SOURCE, type LoadFederatedOptions, type LoadSessionEntriesOptions, type LoadTaskEntriesOptions, type LoadedApproval, type LockHandle, type LockScope, MANIFEST_SCHEMA_VERSION, 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, PROTOCOL_UPDATE_TOKEN_PREFIX, type PrefixedId, type PresetAction, type PresetCollision, type PresetMarkerConflict, type PresetMarkerKind, type PresetPlanSummary, type PresetRepo, type PresetStrings, type ProcessRunner, type ProtocolStamp, 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_IMPORT_SCHEMA_VERSION, SESSION_SCHEMA_VERSION, 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, TASK_SCHEMA_VERSION, 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, ZERO_DURATION_RETIRED_SINCE, acquireLock, appendBasouGitignore, appendChainedEvent, appendChainedEventLocked, appendEvent, appendEventToExistingSession, archiveTask, assertBasouRootSafe, basouPaths, buildJsonSchemas, buildReviewRecordLabel, buildReviewRecordedEvent, buildSessionStartHookCommand, buildStatusSnapshot, buildStopHookCommand, carryForwardProtocolStamp, chainEvents, chainRawJsonLines, classifyFilesBySourceRoot, classifyRetrofit, classifySuspect, claudeCodeAdapterMetadata, claudeTranscriptToImportPayload, codexAdapterMetadata, codexRolloutToImportPayload, computeWorkStats, createAdHocSessionWithEvent, createManifest, createTaskWithEvent, deleteTask, editTask, ensureBasouDirectory, enumerateApprovals, enumerateArchivedTaskIds, enumerateSessionDirs, enumerateTaskIds, evaluateStopHook, finalizeSessionYaml, findBasouSessionStartHook, findBasouStopHookCommand, findDecisionGaps, findErrorCode, findReviewGaps, findUnbindableRepos, formatDurationMs, genesisHash, getDiff, getSnapshot, hasRetiredZeroDuration, importSessionFromJson, inspectChainTail, instructionMode, isBasouSessionStartHookCommand, isBasouStopHookCommand, isGitNotFound, isImportDerivedSource, isLazyExpired, isProtocolUpdateDue, isRenderable, isValidPrefixedId, lineHash, linkYamlFile, loadApproval, loadFederatedSessionEntries, loadSessionEntries, loadTaskEntries, normalizeRepoKey, normalizeRepoPath, overwriteYamlFile, parseBuildStamp, parseDuration, parseMarkers, parseProtocolStamp, parseReviewRecordInput, pathBasename, planArchive, planGitignore, planRename, planRosterAdoption, planWorkspaceView, prefixedUlid, presetStrings, protocolBlockHash, protocolSectionsFrom, protocolUpdateToken, readAllEvents, readManifest, readMarkdownFile, readObservedDuration, readSessionYaml, readStatus, readTaskFile, readTaskFileWithArchiveFallback, readYamlFile, rechainSessionInPlace, reconcileAllTasks, reconcileSourceRoots, reconcileTask, refreshTaskLinkedSessions, reimportPreservingId, removeMarkerSection, removeSessionStartHook, removeStopHook, renderAnchorStarter, renderDecisions, renderHandoff, renderOrientation, renderPresetBlock, renderProtocolStamp, renderProtocolUpdate, 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, transcriptStartedAt, tryRemoteUrl, ulid, unknownManifestKeys, unstampedProtocolSectionsFrom, updateTaskStatusWithEvent, upsertSessionStartHook, upsertStopHook, verifyEventsChain, viewStrings, writeEventsBulk, writeManifest, writeMarkdownFile, writeObservedDuration, writeStatus, writeTaskFile, writeYamlFile };
|